2015-09-04 3 views
8

例:次のコードでは、比較に使用された番号「10」はどのように格納されますか?C言語で宣言されていないエンティティに対してメモリをどのように管理していますか?

#include<stdio.h> 
#include<conio.h> 

int main() 
{ 
    int x = 5; 
    if (x > 10) 
     printf("X is greater than 10"); 
    else if (x < 10) 
     printf("X is lesser than 10"); 
    else 
     printf("x = 10"); 
    getch(); 
    return 0; 
} 

私は十分な詳細を与えてくれていません。 'x'を直接 '5'で初期化するのではなく、スキャンしてユーザーから取得すると、メモリが 'x'にどのように割り当てられているかが分かります。しかし、変数に格納されていないリテラルナンバー '10'にどのようにメモリが割り当てられていますか?

+2

あなたのコードには関係ありませんが、 "Xは10未満です"と言う文法上正しい方法です。 – cjm

+0

他: "*言語*によって"、まったくありません。これは、*実装者*が把握する仕事です。 – Hurkyl

+0

#2:あなたの質問はおそらくタイトルにもかかわらず、あなたの質問に存在するはずです。 – Hurkyl

答えて

12

定数10は、おそらく即値定数としてopcodeストリームに格納されます。オペコードに定数が含まれているCMP AX,10を発行すると、通常、比較値をメモリからロードする必要があるCMP AX, [BX]より小さく高速です。

定数が大きすぎてオペコードに収まらない場合は、静的変数のようにメモリに格納することもできますが、命令セットに埋め込み定数がある場合は、良いコンパイラで使用する必要がありますモードは他のものよりも利点があるため、おそらく追加されました。

+4

"代わりに静的変数のようにメモリに格納する方法があります" - より多くの選択肢があります。 1つまたは2つの命令を発行してレジスタに正しい値を作成することができます(たとえば、制限が7であるために10が大きすぎる場合は7 + 3、その後は比較します)。 –

32

特定のコードでは、xは5に初期化され、決して変更されません。 optimizing compilerconstant foldになり、その情報を伝播できます。だから、それはおそらく、コンパイラはまたdead code eliminationを行っているだろうと

int main() { 
printf("X is lesser than 10"); 
getch(); 
return 0; 
} 

予告の同等のものを生成することになります。

したがって、定数5と10の両方が消えてしまいます。

BTW、<conio.h>およびgetchは、標準C99またはC11には含まれていません。私のLinuxシステムはそれらを持っていません。一般に

(及びターゲットプロセッサのinstruction setABIに応じて)小さな定数はしばしばKilian answeredとして、(即値オペランドなど)いくつかの単machine code命令に埋め込まれています。 code segmentには、いくつかの大きな定数(浮動小数点数、リテラル文字列、大部分はconstグローバルまたはstaticの配列と集合体)が読み込まれ、コンパイルされることがあります(マシンレジスタロード命令内の定数は、 PICの場合はPCthisも参照してください。いくつかのアーキテクチャ(例えば、SPARC,RISC-V,ARMおよび他のRISC)は、2つの連続する命令(2つの部分で定数をロードすること)によってレジスタ内に広い定数をロードすることができ、これはobject filesrelocationフォーマットに影響しますexecutables、多くの場合ELF)。

私はあなたのコンパイラに、アセンブラコードを出すように頼み、そのアセンブラコードを一目見してみることをお勧めします。 GCC(Linuxの場合はCygwinまたはMinGW)を使用している場合はgcc -Wall -O -fverbose-asm -Sでコンパイルしてください。私は取得していますあなたのコード内でgetchargetchを交換する場合は、私のDebian/Linuxシステム上:

 .section  .rodata.str1.1,"aMS",@progbits,1 
.LC0: 
     .string "X is lesser than 10" 
     .text 
     .globl main 
     .type main, @function 
main: 
.LFB11: 
     .cfi_startproc 
     subq $8, %rsp  #, 
     .cfi_def_cfa_offset 16 
     movl $.LC0, %edi  #, 
     movl $0, %eax  #, 
     call printf # 
     movq stdin(%rip), %rdi  # stdin, 
     call _IO_getc  # 
     movl $0, %eax  #, 
     addq $8, %rsp  #, 
     .cfi_def_cfa_offset 8 
     ret 
     .cfi_endproc 
.LFE11: 
     .size main, .-main 
     .ident "GCC: (Debian 4.9.2-10) 4.9.2" 
     .section  .note.GNU-stack,"",@progbits 

を使用すると、64ビットのWindowsシステムを使用している場合は、あなたのアーキテクチャはx86-64可能性が高いです。ISA(thisへの回答を参照)とx86 calling conventions(そしてLinux x86-64 ABI; Windows用の同等の文書があります)を記述するdocumentationのトンがあります。

ところで、実際にこのような定数がどのように実装されているか気にする必要はありません。コードのsemanticsは、コンパイラがそれらを実装するために選択したものであれば、変更すべきではありません。コンパイラ(すなわち、Cの実装)に最適化(とそのような低レベルの選択)を任せてください。

+1

いつものように、非常に包括的で読みやすい。 – Deduplicator

+0

https://gcc.godbolt.orgは、ソースやさまざまなコンパイラをオンラインで見るのに便利です(本質的にgccのフィドルサイト)。最適化をしないでください:https://gcc.godbolt.orgと '-O2':https://goo.gl/GQ7YFn –

+0

@MichaelT:私は' gccbot'について知っていますが、答えにコードをコピーする方が好きです。 –

関連する問題