Programming Serendipity

気まぐれに大まかに生きるブログ

C/C++のちょっと便利な書き方2つ

この記事はC言語 Advent Calendar 2017 19日目の記事です。

ベテランの人にとっては何でもない書き方かもしれませんが、最近(今年)知って新鮮な驚きがあった2つの書き方を載せてみます。

1. オブジェクトの取得とNULL比較を同時に行う(C++only)

Obj* pObj = GetObj();
if(pObj)
{
    //...
}

という処理はよくありますが、以下のように簡略化できます。

if(Obj* pObj = GetObj())
{
    //...
}

初心者のうちは、if文の中に代入は使うな、とよくアドバイスされますし、既存の変数に代入すると警告を出すコンパイラもありますが、これは便利!コンパイラによっては、この書き方に限っては警告を出さないようです。

特に4つくらいチェックするオブジェクトがあるときはコードの行数がぐっと減りますね。

C#の方面では最近のC#7になってようやく1行で書ける文法が出来つつありますが、昔からあるC言語で既に1行で書くやり方があったとは…。

2. 範囲内の数値のインクリメントループを簡略化する

0,1,2,3,4,0,1,2,3,4...という値を取得したい場合に、

x = (x + 1) % 5;

または

x = ++x % 5;

と書けますが、さらに

++x %= 5;

とも書けるようです!すごい! 左辺に三項演算子が使えることは知っていましたが、インクリメントもいけるんですね。

逆に4,3,2,1,0,4,3,2,1,0,...とする場合は

x = (x - 1 + 5) % 5;
x = (--x + 5) % 5;

とは書けても、結局5を足してから最終結果を取らないといけないので、これ以上の簡略化は無理そうです。

--x + 5 %= 5; // ???

除数が2の累乗の場合に、unsigned型を使ってアンダーフローに依存すればできるかもしれませんが、邪道ですね。

追記:はてブコメントでMagicantさんから未定義動作との指摘をいただきました。(規格のどの部分に書かれているかは自分の読解力では見つけられませんでしたが…) 同じ式の別の個所に登場する値をインクリメントしたら未定義動作になるとしたら、この場合最初の書き方しか未定義動作を防ぐことはできないのでしょうか?う~ん…?