0

複数行のマクロをコードのどこにでも安全に含めるには、do while(0) ループで囲む必要があることがわかっています。

たとえば、これは 100% 安全です。

#define swap( a , b )       \
        do                  \
        {                   \
            int t = a ;     \
            a = b ;         \
            b = t ;         \
        }                   \
        while(0)

ループ外のコードの一部を含むマクロを使用することも安全かどうか、そうでない場合は、どのような状況で問題が発生する可能性があるかを知りたいです。

#define swap( a , b )       \
        int t ;             \   //should be in the same scope where the macro was called and before the loop
        do                  \
        {                   \
            t = a ;         \
            a = b ;         \
            b = t ;         \
        }                   \
        while(0)

これを達成するための安全な方法はありますか、何を変更する必要があるか、安全でない場合はどのルールに従う必要がありますか。

4

5 に答える 5

3

多くの点で安全ではありません。まず、t という名前の変数が既に存在していると、コンパイルされません。

それとは別に、次のようなことに注意する必要があります。

if (...)
    swap(a,b);

次のように展開されます。

if (...)
    int t;
    do { ... } while(0);

if ブロックには中かっこがないため、if 本体は単なる宣言になることに注意してください。

do ブロック内で t を宣言しないのはなぜですか?

于 2013-10-01T12:32:09.203 に答える
2

私が考えることができる2つのケース。まず、現在のスコープに変数が既に存在するt場合、複数の定義または競合する定義が同じスコープ エラーになります。次に、次の点を考慮してください。

if (some_condition) swap(a,b);

次のように展開されます。

if (some_condition) int t;
do
{
    t = a;
    a = b;
    b = t;
} while (0);
于 2013-10-01T12:31:43.893 に答える
1

スコープの話以外に、マクロには 2 つ目の問題があります。マクロ変数に括弧を入れるのを忘れました。これは驚くべき効果をもたらす可能性があります。

#define swap( a , b )       \
        do                  \
        {                   \
            int t = a ;     \
            a = b ;         \
            b = t ;         \
        }                   \
        while(0)

C++ では、たとえば 3 項を使用してマクロを呼び出すとswap(x?x:y, z)、驚くべき効果が得られます。

do
  {
  int t = x?x:y;
  x?x:y = z ;
  z = t;
  }
while(0)

3 項は影響よりも優先度が低いため、2 行目は次のように解釈されます。 x?x:(y = z);

他にもサプライズがあるかもしれないので、原則として:

常にマクロ パラメータを括弧で囲んでください。

編集:これは正しいです#define

#define swap( a , b )       \
        do                  \
        {                   \
            int t = (a) ;     \
            (a) = (b) ;         \
            (b) = t ;         \
        }                   \
        while(0)
于 2013-10-01T15:05:41.417 に答える
1

名前付きの変数tがそのスコープ内の他の場所にある場合、コンパイルセーフではありません。

于 2013-10-01T12:29:32.053 に答える
0

実際の目標はt、マクロの外部からのアクセスを定義することであるため、マクロの外部で宣言する必要があります。マクロが 1 つのコード ブロックで複数回使用できるものである場合 (たとえば、複数の値を交換できるようswapしたい場合など)、複数の.t

代わりに、MFC のように実行して、マクロのすべての「グローバル」データを準備USES_CONVERSIONする別のマクロを定義し、各コード ブロックで一度だけ呼び出すことができます。ブロック)。これで、必要な変数の宣言を 1 つのマクロで処理しながら、好きなだけ頻繁に交換することができます。USES_SWAPSWAP

もちろん、t宣言された inUSES_SWAPが他の s と競合するという問題は残りtますが、それを行う別の方法が見つからない場合は、それが必要になるだけかもしれません。これが問題になる可能性を減らすには、swap_tまたは などのより具体的な名前を検討する必要がありますSwapInternalVariable_t。通常のコードでその名前の変数を誰かが宣言する危険性はかなり低いです。

于 2013-10-01T13:00:06.997 に答える