C语言强制类型转换小问题

想必很多同学都在C语言中使用过强制类型转换,不知道有没有碰到什么问题。如果谨慎使用强制类型转换,大多数时候都不会出错。当然,前提是对C语言的内存布局比较熟悉,否则有时候看着语法和逻辑都没有问题,却有可能出现意想不到的结果。

看下面这段代码,猜猜输出结果是什么:

  1 #include <stdio.h>
  2
  3 void *a = 0;
  4
  5 void set(void *p) {
  6         a = p;
  7         printf("a has been set to: %d\n", a);
  8 }
  9
 10 void get(void **p) {
 11         if (p) {
 12                 *p = a;
 13                 printf("get value from a: %d\n", *p);
 14         }
 15 }
 16
 17 int main(void) {
 18         char *s = "hello, world";
 19         printf("string s: %s\n", s);
 20
 21         int data = 1;
 22         printf("save data: %d\n", data);
 23         set((void *)data);
 24
 25         data = 2;
 26         printf("change data to: %d\n", data);
 27
 28         get((void **)&data);
 29         printf("restore data to: %d\n", data);
 30
 31         printf("string s: %s\n", s);
 32
 33         return 0;
 34 }

运行结果如下:

string s: hello, world
save data: 1
a has been set to: 1
change data to: 2
get value from a: 1
restore data to: 1
string s: (null)

程序的意图很简单,就是想用一个全局变量 a 来存储一个 int 类型的变量值,因为该全局变量是指针类型,一般来说,指针类型变量能存放的下 int 类型的值。从运行结果的前6行打印来看,程序执行正常,变量data的值被正确存储和还原了。但最后一行的输出就很怪异了,整个程序中并没有显式的改变指针s的值,但为什么最后s的值为NULL了?不应该存的是"hello, world"字符串常量的地址吗?

第5行的set函数是设置值,其中用到了强制类型转换,这个操作没有问题,但第28行在调用get函数时所用到的强制类型转换就可能有问题了,因为在get函数中,变量p中存放的是main函数中data变量的地址,也就是说,(*p)就是data,给(*p)赋值就是给data赋值,然而,在get函数中,(*p)的类型是指针类型。在上述代码的运行环境中,(*p)占用8个字节,data是int类型,占用4个字节,此时如果给(*p)赋值一个指针,就会影响data变量邻近的其他4个字节。

如果在main函数中添加几行打印,就能看的更清晰明了了。

char *s = "hello, world";
int data = 1;

char *c = (char *)&s;
printf("s addr: %p, s size: %d, s content: 0x%0x, s content's first byte: 0x%0x\n", &s, sizeof(s), s, *c);
printf("data addr: %p, data size: %d, data content: %d\n", &data, sizeof(data), data);

运行结果如下:

s addr: 0x7ffe25b5d530, s size: 8, s content: 0x40077d, s content's first byte: 0x7d
data addr: 0x7ffe25b5d52c, data size: 4, data content: 1

从运行结果来看,我们可以画出如下示意图:

与变量data邻近的就是变量s,在对(*p)进行赋值一个指针后,不仅变量data 的4个字节被改变了,连变量s的部分4个字节也被改变了,对于值为1的指针来说,低4个字节的值是1,高4个字节的值是0,因此当变量s的低4个字节被改变为0后,s的值就为NULL了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值