C语言的单引号问题
C语言的单引号问题
单引号的原理
C语言的单引号实际上时将' '内的字符转化为ASCII码对应的整型值,并且在存储时占据一个字节,即sizeof(char)
// 第一个例子
int main()
{
char ch;
ch = '?';
printf("%d, %c", ch, ch);
// 63, ?
}
输出63, ?
这是因为?对应的ASCII码值为63
现在来看看一个单引号中有两位字符时的情况
// 第二个例子
int main()
{
char ch;
ch = '!?';
printf("%d, %c", ch, ch);
// 63, ?
}
输出竟然还是63, ?
先别急着追问为什么,我们再来看看下一种有些差异的情况
// 第三个例子
int main()
{
printf("%d, %c",'!?','!?');
// 这次的输出变成了8511, ?
}
这其实和上述的原理' '中的字符会被转化为ASCII的整型值 一致
我们来看看8511是如何得到的,从ASCII表上,我们得到!对应33,?对应63
按一个字符一个字节转化为二进制就分别是0010 0001,0011 1111,将它们拼接得到0010 0001 0011 1111,转换为十进制我们得到8511
这就是8511的由来,那为什么在第二个例子中的输出不一样呢?
原来是8511赋值给char类型时发生了溢出,得到的结果就是0011 1111这一个字节,也就是63,从结果上看char得到的就是单引号中的最后一个字符
知道原理后可以用更简便的方式计算,一个数向左移一个字节<< 8,相当于乘以2 ^ 8 = 256
'!?' = 8511
33 * 256 + 63 = 8511
'xyz' = 7895418
120 * 256 * 256 + 121 * 256 + 122 = 7895418
'456789' = 909588537
这次整型值也溢出了,'456789' = '6789' = 909588537
int和char
int和char在很多方面都是相同的
int main()
{
printf("%d, %c\n", 65, 65);
printf("%d, %c\n", 100, 100);
printf("%d, %c\n", 1000, 1000);
printf("%d, %c\n", 10000, 10000);
/*
输出
65, A
100, d
1000, ?
10000,
*/
}
比如:
-
都使用二进制补码法表示正负数;
-
char可以用
%d输出ASCII码,小的整数也可以用%c输出字符,大的字符使用%c相当于经过了一次溢出处理,同样也会输出某个字符。它们最主要的区别在于
int占4个字节,而char占1个字节,理论上'xxxx'(x表示一个字符)可以表示一个int
更复杂的情况
基于以上理论,我们可以有一个有趣的玩法
int main()
{
int a[] = {'1234', 'abcd', 'qwer', 'hjkl', 0};
printf("%s", a);
}
在我的电脑上,这输出4321dcbarewqlkjh
%s实际上也是通过字符指针,来一个个输出字符的,在这个过程中,实际上可以理解为发生了
a = (char *) a
'1234', 'abcd'等经过单引号转变为连续排列的一个个字节,这和字符串的储存方式很像,同时我还加了一个0来结束%s的输出,这就更像了。
可以看到,输出和我们初始化的数字是倒置的,这说明整型的存储是反向的。也就是说在整型存储时,低位字节存在前面的地址,高位字节存在后面的字节。
int main()
{
int a[] = {'1234', 0};
printf("%s\n", a);
// 4321
a[0] <<= 1;
printf("%s\n", a);
// hfdb
}
再找出它们对应的二进制
'1234'对应0011 0001 0011 0010 0011 0011 0011 0100
'4321'对应0011 0100 0011 0011 0011 0010 0011 0001
'hfdb'对应0110 1000 0110 0110 0110 0100 0110 0010
'hfdb'确实是'4321'左移一位后的结果。

浙公网安备 33010602011771号