1

この質問のコードを少し変更したバージョンを次に示します。

#pragma warning(default:4716)
int recur(int i) 
{ 
   int result;
   result = (i>1 ? i - recur(i/2) : 3);
   // return intentionally omitted
}

int main()
{
    return recur(0);
}

recur()省略されreturnているため、その動作は未定義であることに注意してください。このコードに対して Visual C++ 10 が出力するものは次のとおりです。

 316: int main()
 317: {
00403940  push        ecx  
 318:   return recur(0);
00403941  mov         eax,dword ptr [esp]  
 319: }
00403944  pop         ecx  
00403945  ret

はい、未定義の動作の場合は何でも許可されることを知っています。しかし、このコードは完全に無意味であり、コンパイラーはプログラムであるため、無意味なことは期待できません。

コンパイラはどのようにして完全に無意味なコードを発行するのでしょうか?

4

2 に答える 2

1

コードの動作は未定義であるため、コンパイラーは無意味なコードの生成を含め、文字通り何でも実行できます。

ここで発生した可能性が最も高いのは、コンパイラーがコードを忠実にコンパイルし、オプティマイザーに渡して、インライン化と定数式の折りたたみを行ったことです。
壊れたコードでそのプロセスを使用すると、たまたま見たものになります。

于 2013-01-22T08:47:20.327 に答える
1

コンパイラの観点からreturn smth;、ステートメントは単純なことを意味します。呼び出し規則に従って呼び出し元に結果を返すコードを生成します(これは、「C」、x86/amd64、および自明な型の場合、通常はeax/raxレジスタに置くことを意味します)。見逃した場合、returnこれは、そのようなコードを生成しないことをコンパイラに意味するだけです ( mov result, %eax)。通常、これは (少なくとも) 警告につながります: non-void を返す関数に return ステートメントはありません。しかし、関数本体にコンパイラの代わりにそれを行う部分がある場合、それはまったくasm問題ありません...その(まれな)ケースでは、警告は通常 #pragma または対応するコマンドラインオプションによって抑制されます。はい、一般的に、リターンを逃すとUBにつながります...

于 2013-01-22T07:41:53.837 に答える