如下代码输出什么:
#include<stdio.h>
int main()
{
char a=0;
char b=0;
int *p=(int *)&b;
*p=258;
printf("%d %d",a,b);
return 0;
}
在看国外一本linux方面的书,里面讲到c语言内存布局相关,书中说这个程序运行结果是1 2,可是我再我的电脑(mac)上运行时02,并且想不明白这是为什么.
我目前仅有的思路如下:
258的二进制形式100000010
指针p指向了字符b的起始地址,字符与整形的地址对比可以通过下面的代码得出:
#include <stdio.h>
int main()
{
char a = 0;
char b = 0;
char c = 0;
int d = 0;
int e = 0;
int f = 0;
printf("%p\n",&a);
printf("%p\n",&b);
printf("%p\n",&c);
printf("%p\n",&d);
printf("%p\n",&e);
printf("%p\n",&f);
return 0;
}
代码输出
0x7fffc38df0df
0x7fffc38df0de
0x7fffc38df0dd
0x7fffc38df0d8
0x7fffc38df0d4
0x7fffc38df0d0
地址由高到低,所以我的理解是*p复制258(258的二进制形式100000010)会去覆盖字符a b 原有的值,所以b的值是00000010 a的值是000000001,a的值是1,b的值是2.此时涉及到大端与小端方式,我通过如下程序判断出我电脑环境为小端方式:
#include <stdio.h>
#include <string.h>
union u_tag
{
short s;
char c[sizeof(short)];
}un;
int main(int argc, const char * argv[])
{
un.s = 0x0102;
//打印数组c中地址关系
printf("%p %p\n",&un.c[0],&un.c[1]);
if (sizeof(short) == 2) {
if (un.c[0] == 1 && un.c[1] == 2)
printf("big-endian\n");
else if (un.c[0] == 2 && un.c[1] == 1)
printf("little-endian\n");
else
printf("unknown\n");
}
else
{
printf("sizeof(short) = %lu\n", sizeof(short));
}
return 0;
}
可是我实际运行中确实0 2.
估计你开了编译器优化。
我的环境:
Ubuntu 16.04 (64 bit)
gcc 5.4.0
不开优化直接编译,结果的确是
1 2
;但一旦开了优化(-O1
,-O2
,-O3
,-Og
结果都一样,其中-Og
会报错),结果就变成了0 2
。原因在于:编译器在编译阶段就已经将值算好了,你输出的其实是常量。拿
-O1
优化的汇编代码举例(使用gcc test.c -O1 -S
获得,这里只贴核心部分):%edi
,%esi
,%edx
,%ecx
分别是__printf_chk
的参数,%esi
指向%s %s
的地址。可以发现最后两个参数并没有访问栈区,而是直接使用了立即数 0 和 2,可见这两个值的计算在编译期就已经完成了。