2015-09-04 42 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; 
} 

對不起,我沒有給予足夠的細節。不是直接用'5'初始化'x',如果我們掃描並從用戶那裏得到它,我們知道內存是如何分配給'x'的。但是,如何將內存分配給未存儲在任何變量中的文字數字「10」?

+2

與您的代碼無關,但「X小於10」是語法正確的說法。 – cjm

+0

另外:「通過*語言*」,根本沒有。這是*執行者*的一項工作。 – Hurkyl

+0

除了#2:你的問題可能應該出現在你的問題中,即使它恰好也在標題中。 – Hurkyl

回答

12

常量10可能存儲爲操作碼流中的立即數。發出CMP AX,10(包含在操作碼中的常數)通常比CMP AX, [BX]更小且更快,其中比較值必須從內存加載。

如果常量太大而無法放入操作碼,另一種方法是將其作爲靜態變量存儲在內存中,但如果指令集允許嵌入常量,那麼優秀的編譯器應該使用它 - 畢竟,尋址模式可能被添加,因爲它具有優於其他模式的優點。

+4

「另一種方法是將它像靜態變量一樣存儲在內存中」 - 還有更多的選擇。您可能會發出一條或兩條指令,以在寄存器中構造正確的值(例如7 + 3,如果10對於立即過大,因爲限制爲7),然後進行比較。 –

32

在您的特定代碼中,x已初始化爲5並且從未更改過。 optimizing compiler能夠constant fold並傳播該信息。因此,它可能會產生

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

通知相當於編譯器也將這樣做dead code elimination

因此,常量5和10都會消失。

BTW,<conio.h>getch不在標準的C99或C11中。我的Linux系統沒有它們。

通常(並且取決於目標處理器的instruction setABI)小常數通常嵌入在一些單machine code指令(如立即操作數),作爲Kilian answered。一些大的常量(例如浮點數,文字字符串,大多數const global或static數組和聚合體)可能被插入並編譯爲code segment中的只讀數據(然後機器寄存器加載指令內的常量將是地址或某些偏移量相對於PCPIC);另見this。一些架構(例如SPARCRISC-VARM,和其它RISC)能夠由兩個連續指令(加載在兩個部分的常數),並且該衝擊relocation格式來加載在寄存器中的寬常數linker(例如,在object filesexecutables,通常在ELF)。

我建議要求你的編譯器發出彙編代碼,並且瀏覽一下這個彙編代碼。如果使用GCC(例如在Linux上,或者使用CygwinMinGW)嘗試使用gcc -Wall -O -fverbose-asm -S進行編譯;我的Debian/Linux系統上,如果我在你的代碼替換getch通過getchar我越來越:

 .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。有大量documentation描述ISA(請參閱this的答案)和x86 calling conventions(還有Linux x86-64 ABI;您可以找到Windows的等效文檔)。

順便說一句,你不應該真的在乎這些常量是如何實現的。代碼的semantics不應更改,無論編譯器選擇如何實現它們。因此,將優化(以及這樣的低級選擇)留給編譯器(即您的C實現)。

+1

一如既往,非常全面,很好閱讀。 – Deduplicator

+0

我發現https://gcc.godbolt.org常常用於在線查看源代碼和不同的編譯器 - 本質上是一個gcc小提琴網站。沒有優化:https://gcc.godbolt.org和'-O2':https://goo.gl/GQ7YFn – 2015-09-04 15:23:06

+0

@MichaelT:我知道'gccbot',但我更喜歡在答案中複製代碼。 –