C語言裡為何會有「2 2 5」的結果

2021-12-30 00:06:52 字數 2484 閱讀 2359

int main()

有些童鞋可能會說,這不是偷換概念嗎,拿字串和int相加,是滴,但在這裡請這些童鞋暫且幽默一回,想一想為何a+b會得出5的結果?你們實際動手編譯了嗎?結果是為5嗎?

我動手編譯了,結果不是5,確切的說是乙個不可列印的ascii字元,所以console顯示的是:2+2= ,稍對c堆疊布局略有了解的都知道,其實這段**最後試圖列印的是__func_version__裡的字串"5",但遺憾的是不同編譯器,甚至同一種編譯器用不通編譯選項生成得stack布局是截然不同的,這就無法保證精確定位b之後3位元組正好指向__func_version__。

那麼在gcc -o3下到底布局如何呢?我們略微修改一下**:

#include

int main()

*/ printf("%d + %s = %s\n", a, b, a+b);

return 0;

}我們來看一下結果:

gcc -v

using built-in specs.

collect_gcc=gcc

collect_lto_wrapper=/usr/local/cellar/gcc48/4.8.2/libexec/gcc/x86_64-apple-darwin13.0.0/4.8.2/lto-wrapper

target: x86_64-apple-darwin13.0.0

configured with: ../configure --build=x86_64-apple-darwin13.0.0 --prefix=/usr/local/cellar/gcc48/4.8.2 --enable-languages=c,c++,objc,obj-c++ --program-suffix=-4.8 --with-gmp=/usr/local/opt/gmp4 --with-mpfr=/usr/local/opt/mpfr2 --with-mpc=/usr/local/opt/libmpc08

--with-cloog=/usr/local/opt/cloog018 --with-isl=/usr/local/opt/isl011 --with-system-zlib --enable-version-specific-runtime-libs --enable-libstdcxx-time=yes --enable-stage1-checking --enable-checking=release --enable-lto --disable-werror --enable-plugin --disable-nls

--disable-multilib

thread model: posix

gcc version 4.8.2 (gcc)

cs$gcc -std=c99 -wall -o3 -g0 -o 5 5.c

apple@kissair: cs$./5

0x7fff504fa920 0x7fff504fa930 0x7fff504fa910

2 + 2 = op?

納尼!腫麼__func_version__還比b要小,那麼不管b加什麼正數都無法指向前者了,當然有些人會說了,可以整數迴繞啊,我呵呵了。那也不行哦,那樣就不是「2+2=5」鳥,而是"2+*********x=5"鳥了哦。雖然可以改變兩個字元陣列變數的位置來解決這一問題,即b定義放在__func_version__前面,但那也要"2+16=5"哦,我不知道gcc有沒有什麼編譯選項可以pack堆疊變數滴,但我知道#pragma pack(1)是可以打包結構變數滴,so很簡單的我們可以新增如下**:

#pragma pack(1)

typedef struct __foo foo;

void print_5_by_struct(void)

; printf("%p %p\n",foo_v.__func_version__,foo_v.b);

printf("%d + %s = %s\n",foo_v.a,foo_v.b,foo_v.a+foo_v.b);

}最終如願以償的列印了「2+2=5」,如果有其他童鞋知道gcc如何pack變數布局的,請告知本貓,在此感謝。

有些童鞋又會說了,你這樣結構太累贅鳥,太墨跡,不爽快!也好辦,沒說只能用gcc啊,我們試試clang吧 :)

#include

int main()

shell編譯執行如下:

clang -v

apple llvm version 5.1 (clang-503.0.40) (based on llvm 3.4svn)

target: x86_64-apple-darwin13.2.0

thread model: posix

apple@kissair: cs$clang -std=c99 -wall -o3 -g0 -o 5 5.c

apple@kissair: cs$./5

0x7fff57925936 0x7fff57925934 0x7fff57925933

2 + 2 = 5

所以說學c啥的光死看書不中啊,要學以致用啊,在此拋磚引玉,謝謝各位觀賞哦。

C語言裡的for

for迴圈感覺是比較有技術含量的乙個知識點,很容易繞暈過去,特別是for迴圈的巢狀語句,總是有種不知道應該怎麼往下看的無措感。但是for迴圈其實還有點意思,特別是在我用它能輸出菱形之後,越發覺得好神奇。首先總結for的知識點 格式如下 for 表示式1 表示式2 表示式3 語句表示式1 賦初值,只執...

C語言巨集裡 的用法

c 和c 中的巨集 macro 屬於編譯器預處理的範疇,屬於編譯期概念 而非執行期概念 下面對常遇到的巨集的使用問題做了簡單總結。關於 和 define warn if exp do while 0 那麼實際使用中會出現下面所示的替換過程 warn if divider 0 被替換為 do whil...

c語言裡NULL的理解

null一看名字就知道為空,什麼為空呢,而且全是大寫。是不是意味著是個巨集定義呢?如果想到這裡,我相信你離真理不遠了。有些人為什麼犯錯?因為只看到了null這四個字母而已,沒有看到事物的本質,老師在課堂上也只是說空指標,空字串。這樣只會陷入無止境的誤區。如果我這樣定義 define null 0 你...