这段C语言程序虽然很简单,但是我工作多年的同事还是弄错了

前两天,我在我的圈子里发了一个小问题,相关的C语言代码如下,这段程序会输出什么呢?

#include

int main()

{

signed char a = (unsigned char)-1;

unsigned char b = a;

int c = a;

int d = b;

printf("%d %d %d %d", a, b, c, d);

return 0;

}

这段C语言程序会输出什么呢?

题外话

在分析这个问题之前,先说些题外话。有程序员认为研究这样的代码没有意义,无异于孔乙己的“茴”字有几种写法。

这个问题其实并不是我空想出来的。

这个问题其实并不是我空想出来的。

最近,我的一个同事被他的C语言程序 bug 困扰了好几天,始终无法找到问题究竟出在哪里,于是找我,我看到他的C语言代码混用了无符号变量和有符号变量,于是就提醒他注意这个方面,后来发现果然是这个原因。

他的问题涉及到比较复杂的项目,完整的复述一遍不太现实,于是我把他的问题精简一下,就构成了上述C语言代码段。

事实上,很多公司招聘时,都有一些面试题或者笔试题看起来很怪异,很不符合标准的开发规范,于是有些程序员就认为做这样的面试题是完全没有意义的,甚至觉得做这些题目是一种侮辱。

C语言是一门极其重视基本功的编程语言

其实换个角度想想,这些题目很能考察一个人的基本功,它们很可能来自公司内部的某个项目的某次重大 bug。C语言是一门极其重视基本功的编程语言,这些题目很能查漏补缺。

分析

现在来考虑上面这段C语言代码,我们编译并执行它,得到了下面的输出:

# gcc t.c

# ./a.out

-1 255 -1 255

C语言程序的输出出乎了一些朋友的预料,-1 容易理解,255 是怎么回事呢?

首先要明白的是,在计算机中,整数通常采取补码的形式存储。负数的补码等于其反码+1,负数的反码符号位不变,数值为按位取反。对于 signed char 型变量,大部分C语言编译器都是由 8 个 bit 组成的,最高一个 bit 通常表示符号位。

负数的补码等于其反码+1

所以对于 -1,其原码原本是 0b10000001,但是计算机内部存储该数值时,是以补码形式存储的。-1 的补码等于反码+1,也即 0b11111110 +1 = 0b11111111 = 0xff。

到这里就清楚了,变量 b 在内存里的 8 个 bit 都是 1,它是一个 unsigned char 型的变量,最高 bit 也表示数值,也即 b 等于 255。

现在再来分析变量 c 和变量 d 的值,它俩都是有符号型的 int 型。按理说,a 和 b 在内存中的布局是一样的,都是 8 个 bit 的 1,为什么传递给 c 和 d 就不一样了呢?

整形提升

其实C语言在处理 c = a; 和 d = b; 这两句赋值语句时,有一个过程没有显式的表现出来,即“整形提升”。以 c=a; 为例,因为 c 和 a 的数据类型不同,所以C语言在处理赋值时,为了不丢失精度,会将 a 中的数值也强制转换为 int 型。

a 中的数值是 -1,提升为 int 型后依然是 -1,而不是 0x000000ff(255,这里假设 int 类型占用 4 字节内存空间)。至于变量 d 的值,就更简单了,就是简单的赋值而已。

小结

本节讨论的问题虽然很简单,但是仍然有很多人做错,这其中也包含我工作多年的同事。C语言是一门极其重视基本功的编程语言,事实上,本节涉及的知识点非常基础,无非就是原码补码,以及整型提升的相关知识。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券