背景:近期翻看《C primer plus》第6版,书中在第四章有写不匹配的整形转换的代码和分析。虽然书中的分析思路可以解释的通,但是我认为还有一种更偏向底层的分析思路会更直观,所以写这篇文章记录下,如有错误敬请大家批评指正。
本文布局:第一部分是不匹配的整形转换代码(基于书中的代码的基础上做了些修改),第二部分是该代码对应的输出结果的截图,第三部分尝试从机器码这样偏底层的角度来解释这样的结果,第四部分谈下我对本文中的这种偏向底层的分析思路的想法。
一、不匹配的整形转换代码
#include <stdio.h>
#define PAGES 336
#define WORDS 65618
int main(void)
{
short num = PAGES;
short mnum = -PAGES;
int num2 = WORDS;
int mnum2 = -WORDS;
printf("num as short and unsigned short:%hd, %hu\n",num,num);
printf("-num as short and unsigned short:%hd, %hu\n", mnum, mnum);
printf("-WORDS as int and unsigned int:%d, %u\n", mnum2, mnum2);
printf("-WORDS as short and unsigned short:%hd, %hu\n", mnum2, mnum2);
printf("-WORDS as signed char and unsigned char:%hhd, %hhu\n", mnum2, mnum2);
return 0;
}
二、该代码对应的输出结果的截图
三、基于机器码这样更偏底层的角度来分析
稍微接触过计算机的同学应该都知道,计算机中的数据都是用0、1这样的二进制码表示的,关于数字的表示大家也都有学过原码、反码、补码,在此都不再赘述。但是有两点需要强调:第一,原码的存在是为了让我们人脑计算该二进制码所代表的十进制数;第二,反码的存在是为了机器内部来存储、运算数据。这2点非常重要,接下来我们就基于这2点从更底层的角度来分析上述代码的结果。
PAGES对应的原码 00000000 00000000 00000001 01010000
-PAGES对应的原码 10000000 00000000 00000001 01010000
-WORDS对应的原码 10000000 00000001 00000000 01010010
PAGES对应的补码 00000000 00000000 00000001 01010000
-PAGES对应的补码 11111111 11111111 11111110 10110000
-WORDS对应的补码 11111111 11111110 11111111 10101110
如上由于PAGES \ WORDS 都是signed int类型的(-PAGES \ -WORDS同理),都占有4个字节(对C语言来说不同的系统int类型占用的字节数略有差异,此处默认与我的系统一样均为4个字节)。我们可以根据这两个常量对应的值,用程序员模式的计算器算出其原码,然后根据正数、负数中原码与补码的关系求出其对应的补码(如上已列出)。
由于short类型在我的系统中是2个字节,所以num在计算机内部的补码是PAGES对应补码的后两个字节,即为00000001 01010000。由于num是signed short类型的正数,所以num as short and unsigned short对应的原码都与补码一致,即 00000001 01010000,对应的十进制数即为336
mnum(即-num)在计算机内部的补码是-PAGES对应补码的后两个字节,即11111110 10110000。signed short是带符号的,第一位是符号位,该符号位上是1代表负号,所以-num as short对应的原码是 10000001 01010000,对应的十进制数即为-336;而unsigned short是不带符号的,都是正数,而正数的原码与机器内存储的补码相同,所以as unsigned short对应的原码是 11111110 10110000,对应的十进制数即为65200
与-PAGES类似,-WORDS as int对应的原码是 10000000 00000001 00000000 01010010,对应的十进制数即为-65618,as unsigned int对应的原码是 11111111 11111110 11111111 10101110,对应的十进制数即为4294901678
与-num类似,-WORDS as short对应的补码是11111111 10101110,所以原码是 10000000 01010010,对应的十进制数即为-82,as unsigned short对应的原码是 11111111 10101110,对应的十进制数即为65454
同理,-WORDS as signed char对应的补码是10101110,所以原码是 11010010,对应的十进制数即为-82, as unsigned char对应的原码是 10101110,对应的十进制数即为174
四、关于此种分析思路的一点想法
此分析思路的优点非常明显,无需死记不匹配的整形转换的规律,只需知道原码和反码的本质即可根据这一思路分析出结果。不过值得注意的是,C语言在不同的系统中,各个整数类型所占的字节数可能会略有差异。