0

これが私が試したコードです。得られた出力を理解できませんでした。なぜここに10ではなくガベージ値が出力されるのですか?

#include<stdio.h>
#include<string.h>
void f(int);
void (*foo)(float)=f;
int main()
{

  foo(10);
   return 0;

}

void f(int i)
{
   printf("%d\n",i);
}

出力はごみの値です。

4

5 に答える 5

4

これは未定義の動作です。

fをとる関数である、を呼び出しています。これは、をとる関数intであるかのようにfloatです。実際の動作は、プラットフォームの呼び出し規約がどのように機能するかによって異なります。たとえば、intパラメータfloatが同じレジスタまたは同じスタックスロットで渡された場合、結果は、として表さ10.0fれる浮動小数点ビットパターンのエイリアスになりintます。一方intfloat異なる方法で渡された場合、結果は適切なレジスタまたはスタックスロットにあったガベージになります。

また、これは未定義の動作であるため、コンパイラーは自由に好きなことを実行できます。オプティマイザーが有効になっている場合は、実行できる可能性があります。

于 2012-06-25T12:18:30.103 に答える
4

この場合、コンパイラは通常、警告またはエラーを出力します。たとえば、GCC は次のように言います。

program.c:4: warning: initialization from incompatible pointer type

Intel C Compiler はより詳細です。

program.c(4): warning #144: a value of type "void (*)(int)" cannot be used to initialize an   entity of type "void (*)(float)"
  void (*foo)(float)=f;
                     ^

引数値10を浮動小数点に変換する以外に、64 ビット マシンで実行している場合は別のオプションがあります - 呼び出し規則です。整数引数は通常の整数 CPU レジスタ ( 、 など) を介して渡されますがRDIRSI浮動小数点引数は SSE レジスタ ( XMM0XMM1など) で渡されます。何らかの形で浮動小数点値が整数値と互換性があったとしても、呼び出された関数はXMM0、値を参照するレジスタ ( ) とは異なるレジスタ ( ) で引数を受け取りRDIます。

32 ビット マシンでは、整数引数と浮動小数点引数の両方がスタックに渡されます。最終的に109261619210.0、IEEE 754 単精度浮動小数点表現だけです。

1092616192 = 0|10000010|01000000000000000000000
             | |        |
             | |        +---> significand = 1 + 2^(-2) = 1.25
             | |
             | +------------> exponent = 130 - 127 = +3
             |
             +--------------> sign = 0 (positive)

1.25 * 2^3 = 1.25 * 8 = 10.0
于 2012-06-25T12:33:29.173 に答える
2

未定義の動作のため。

呼び出し throughfoo()は整数10をに変換しfloat、これは by として解釈さintf()ます。

これが明確に定義されていないことは確かです。

于 2012-06-25T12:13:58.750 に答える