有时候错误的代码会让我们更深刻的理解一门编程语言,所以在Learn c the hard way一书中,作者不停的让我们把正确的代码破坏掉,发挥我们的好奇心与想象力,去发觉c语言的一些特性。
为了弄清弄清c中int与char型变量存储的异同和gcc对无‘\0'字符数组的的反应,修改了Learn c the hard way书中的ex8
代码如下
#include <stdio.h>
int main(int argc,char *argv[])
{
int areas[] = {10, 12, 13, 14, 20};
char name [] = "Zed";
char full_name[] = {
'Z', 'e', 'd',
' ', 'A', '.', ' ',
'S', 'h', 'a', 'w'
};
unsigned int interg[2];
interg[0] = '\0' * 0x01000000 + 'A'*0x00010000 + 'B' * 0x00000100 + 'C' * 0x00000001;
unsigned int inter = interg[0];
// WARNING: On some system you may have to change the
// %ld in this code to a %u since it will use unsignt ints
printf("The size of an int: %ld\n",sizeof(int));
printf("The siez of areas (int[]):%ld\n",
sizeof(areas));
printf("The number of ints in areas: %ld\n",
sizeof(areas)/sizeof(int));
printf("The first area is %d, the 2nd %d.\n",
areas[0],areas[10]);
printf("The size of a char: %ld\n",sizeof(char));
printf("The size of name (char[]): %ld\n",
sizeof(name)/sizeof(char));
printf("The size of full_name (char[]): %ld\n",
sizeof(full_name));
printf("The number of chars: %ld\n",
sizeof(full_name) / sizeof(char));
// !!!其中full_name未设置null结尾
printf("name=\"%s\" and full_name=\"%s\"\n",
name, full_name);
// test 证明了gcc把未初始化的地方初始为0
printf("the char after the full_name(shuold be error):%c\n",full_name[12]);
// 用 int 存储字符串
printf("interg=%X\n", interg);
printf("inter=\"%s\"\n", &inter);
printf("interg=\"%s\"\n", interg);
return 0;
}
重点在于
char full_name[] = {
'Z', 'e', 'd',
' ', 'A', '.', ' ',
'S', 'h', 'a', 'w'
};
unsigned int interg[2];
interg[0] = '\0' * 0x01000000 + 'A'*0x00010000 + 'B' * 0x00000100 + 'C' * 0x00000001;
unsigned int inter = interg[0];
可以看到full_name字符串初始化的时候是没有null结尾的,如果的vc中编译并以字符串形式输出的话会跟上乱码
interg的数组第一个元素中我分别在四个字节中放入了‘\0'(即0)、'A'、'B'、’C',第二个元素未初始化。
inter中放的是同样的数字。
输出如下:
The size of an int: 4
The siez of areas (int[]):20
The number of ints in areas: 5
The first area is 10, the 2nd -1493946707.
The size of a char: 1
The size of name (char[]): 4
The size of full_name (char[]): 11
The number of chars: 11
name="Zed" and full_name="Zed A. Shaw"
the char after the full_name(shuold be error):
interg=6EB11E70
inter="CBA"
interg="CBA"
可以看到以字符串输出的full_name并没有因为无null结尾而输出乱码或错误,在chinaunix论坛上了解到可能是因为gcc将字符串存储区全部初始化为零:
从编译器角度上说, 引用非NULL-Terminal的字符串的动作只能听天由命, 乱不乱码和编译器,OS,运行时机有关。
可能的原因:
VC的DEBUG模式下, 会用0xcd(或0xcc)来填充未知空间(或待引用空间),做为越界访问的一种检测手段。
出于安全原因, Linux会将未知空间(指Malloc或是程序空间)清0, 这个0正好起了结束符的使用, 这就是你看到的gcc下引用非null-terminal字串不会乱码的原因。(原帖地址http://bbs.chinaunix.net/thread-4075429-1-1.html)
PS:对于数组的初始化,可以只初始化一个元素,就可以使其他元素为零(Learn c the hard way);
inter以字符串输出的结果是按我赋值的倒序输出的,这个是因为小端的数据存储造成的。
???????????????????????????????
??不过对于interg按十六进制输出的结果不太明白。。。。待解。
???????????????????????????????
这里有一篇说明如何利用这个特性如何判断cpu大端与小端http://www.hztarena.org/Html/soft/201212/1760.html
人家这才是专业的啊。。。。。