2017-03-17 4 views
0

なぜ異なる値を印刷するのですか?詳細に説明してください。 1つのファイルは次のとおりです。私はP2とのchar chは同じ値を出力することが期待Cでオブジェクトファイルをリンクする方法は?この特定の状況を説明してください

/* foo6.c */ 
void p2(void); 

int main() 
{ 
    char ch = main; 
    p2(); 
    printf("Main address is 0x%x\n",main); 
    printf("Char value is 0x%x\n",ch); 
    return 0; 
} 

、しかし、彼らは非常に異なる値を印刷している:

/* boo.c */ 
#include <stdio.h> 
char main; 
void p2() 
{ 
printf("0x%X\n", main); 
} 

別のファイルです。 出力は次のとおりです。

0x55 
Main address is 0x401110 
Char value is 0x10 

私はこのような値の背後にある理由を締結することはできません(私は先に述べたように、メインとchar型の値が期待通りに働いたが、p2を出力しない)

+2

'char'はおそらく8ビットであると署名しました。ポインタはおそらく32/64ビットで符号なしです。 Go figure。 – bace1000

+0

"Char"の値が "Main"の最後のバイト(2ニブル)と同じであることに注目してください。つまり、0x10です。 –

+0

1つのオブジェクトファイルでは、mainはcharであり、他方では関数ポインタです。私は2つを結びつけることが定義されているとは思わない。 – PSkocik

答えて

2

char ch = main;だけのcharへのポインタを切り捨てます。実装は定義されていますが、下位8ビットを取得することは理にかなっています。別のコンパイル単位に(初期化されていない)

char mainは変換されず、メモリマッピング直接charに関数ポインタによってコンパイラを愚か者:すなわち未定義の動作です。

(およびprintfで使用されるフォーマットは、データ型と一致していません...)

それを試してみてください:char main=12;あなたは、多重定義されたシンボルmainを得るでしょう...

+0

未定義の振る舞いは確かに最終行です。さらに、元のコードでも動作が未定義であることに注意してください。ここで、boo.cは 'main'の初期化子を提供しません。 –

0

その確かに未定義の動作、ちょうど追加する - なぜあなたはp2から0x55を参照してくださいか、ディスアセンブリを見て:

p2: 
... 
0x40052a: movzx eax,BYTE PTR [rip+0x17]  # 0x400548 <main> 
... 
main: 
0x400548: push rbp 

gccが機能メインアドレスで最初のバイトを取るコードを生成し、効果的にそれはOです0x55

あるpush rbpためのPコードは、あなたはそれをよりよく理解するために、このように、P2のコードを書き換えることができます。

int main(); 
void p2() { 
    char t = ((char*)&main)[0]; 
    printf("%x\n", t); 
} 
関連する問題