C语言bool占用4个字节?汇编之下无秘密|带你看extern
扫描二维码
随时随地手机看文章
昨天群友发文询问,为什么C语言里bool似乎占用4Byte,给bool赋值后,它后面的3个字节 内容也被修改了,并且她还强调代码没有经过编译器优化(-O0是关闭优化的意思)。
群友很是细心,生成map文件检查bool类型占用的空间,也确认是1字节。
我建议他“反汇编源码,汇编之下无秘密”。
反汇编后确认给变量赋值的汇编指令是"STR",在arm架构下STR指令操作数占4Byte。
最终它找到原因是在extern变量时写错变量类型为int,以至于本应用STRB指令的地方误用成STR。
extern写时一时爽、排故火葬场。
编译器才不管你原始变量定义成什么类型,extern让他看到什么类型他就认为是什么。读书时看老师的代码,很疑惑为什么简单返回变量值,没任何逻辑和运算操作,却要封装成一个函数。
老师笑笑:“Too yong Too simple。”
源码
他的源码复现方式我写在下面,bool类型是C99引入的。
// bool.c ------------------------------------- bool b_a = true;char c_a = 'a';char c_b = 'b';char c_c = 'c'; void fun_print() { printf("%2x %2x %2x %2x\r\n", b_a, c_a, c_b, c_c);} // main.c ------------------------------------- extern int b_a; // 这里不一样extern void fun_print(); void main(){ printf("原始值:"); fun_print(); b_a = false; printf("修改后:"); fun_print();}
arm-linux-gcc *.c ./a.out 原始值: 1 61 62 63修改后: 0 0 0 0
extern引发的错误,就算生成map文件也是看不出的,下面能看到b_a仅占用1Byte, 后面紧跟着c_a变量
arm-linux-gcc *.c -Wl,-Map=gcc.map cat gcc.map | grep b_a -C 3 0x00011028 0x4 /tmp/ccmJQHpj.o 0x00011028 b_a 0x00011029 c_a 0x0001102a c_b 0x0001102b c_c
汇编之下无秘密
arm-linux-objdump -S a.out > b.dis
被错误声明成整型。
-
-
-
-
-
extern int b_a; b_a = false; 843c: e59f3024 ldr r3, [pc, 8440: e3a02000 mov r2, 8444: e5832000 str r2, [r3]
正确声明成布尔类型。
-
-
-
-
-
extern bool b_a; b_a = false; 843c: e59f3024 ldr r3, [pc, 8440: e3a02000 mov r2, 8444: e5c32000 strb r2, [r3]
思考
查阅stdbool.h源码,C语言并没有对true和false特殊定义,而是直接定义成1和0,相当于 true和false都占用4byte。
思考:既然C语言根本没有1bit的类型,那么它是怎么实现bool类型“逻辑判断”的呢?
你可以像我上文那样反汇编看看。再思考按照反汇编的运作方式,它会遇到什么坑?