我写了下面的示例程序,但是他们的输出并不是我所期望的
在我的第一个程序中,s
包含一些字符,但其中一个字符大于127(0xe1
)。当我打印s
时,输出不符合我的预期。
#include <stdio.h>
int main()
{
int i, len;
unsigned char s[] = {0x74, 0x61, 0x6f, 0x62, 0xe1, 0x6f, 0x63, 0x64, 0x6e};
for (i = 0; i < sizeof(s) / sizeof(unsigned char); i++) {
printf("%c ", s[i]);
}
printf("\n%s\n", s);
return 0;
}
猜猜是什么?产出是:
t a o b c d n
taobn@
然后我对第一个程序进行了一些小改动,这是我的第二个程序:
#include <stdio.h>
int main()
{
int i, len;
unsigned char s[] = {0x74, 0x61, 0x6f, 0x62, 0xe1, 0x6f, 0x63, 0x64, 0x6e};
// Iteratively output was deleted here
printf("%s\n", s);
return 0;
}
输出也令我惊讶,他们是:
taobn
要检查这是否是glibc
的一个奇怪特性,我写了第三个程序绕过glibc
的I / O缓冲区并将s
直接写入文件{{1系统调用。
write
产出仍然是:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd;
unsigned char s[] = {0x74, 0x61, 0x6f, 0x62, 0xe1, 0x6f, 0x63, 0x64, 0x6e};
if((fd = open("./a.out", O_WRONLY | O_CREAT)) < 0) {
printf("error open\n");
return -1;
}
write(fd, s, sizeof(s));
close(fd);
return 0;
}
任何人都能解释一下吗?这是怎么回事?
感谢。
答案 0 :(得分:7)
调用带有变量printf("\n%s\n", s)
的{{1}}而不指向以null结尾的字符串会产生未定义的行为。简单来说,数组中的最后一个字符应为0(a.k.a。s
)。
\0
告诉%s
打印位于输入参数指向的内存地址的字符,直到遇到0字符。
您传递的字符数组不包含0个字符,因此printf
将继续从内存中读取字符,直到遇到0或执行非法内存访问。
以下是您最终打印printf
的方法:
您的角色数组是:
"taobn@"
假设位于此数组后面的字符在内存中是:
unsigned char s[] = {0x74, 0x61, 0x6f, 0x62, 0xe1, 0x6f, 0x63, 0x64, 0x6e};
所以实质上,0x08, 0x08, 0x08, 0x08, 0x08, 0x6e, 0x40, 0x20, 0x20, 0x20, 0x08, 0x08, 0x08, 0x00
将尝试打印以下以空字符结尾的字符串:
printf
现在,尝试拨打unsigned char s[] = {0x74, 0x61, 0x6f, 0x62, 0xe1, 0x6f, 0x63, 0x64, 0x6e,
0x08, 0x08, 0x08, 0x08, 0x08, 0x6e, 0x40, 0x20, 0x20,
0x20, 0x08, 0x08, 0x08, 0x00};
,看看你得到了什么......
答案 1 :(得分:5)
除了其他人注意到当前非空字符串终止(可能导致未定义的行为)的问题之外,代码大于127的字符输出取决于当前的控制台字符集。
你可以拥有像ISO-8859-1(AKA Latin1)这样的单字节字符集,或者它的微小变化Windows 1252,CP850或CP437,每个都有自己的高字符表示,但其中一个字节是一个字符,和另一边的UTF8等多字节字符集。
作为示例,字符串éè
由ISO-8859-1中的{ 0xe9, 0xe8, 0 }
,CP850中的{ 0x82, 0x8a, 0 }
和UTF8中的{ 0xc3, 0xa9, 0xc3, 0xa8, 0 }
表示
目前,当您尝试在控制台中打印代码未知的字符时,您可以获得?
,正方形或不存在,具体取决于系统。
答案 2 :(得分:1)
打印单个字符与打印字符数组不同,不会以空终结符终止
unsigned char s[] = { 0x74, 0x61, 0x6f, 0x62, 0xe1, 0x6f, 0x63, 0x64, 0x6e };
printf("\n%s\n", s); // Wrong, undefined behavior
或者你可以自己提供尺寸
printf("\n%.*s\n", (int)sizeof(s), s);
。数
对于s:这是要打印的最大字符数。默认情况下,将打印所有字符,直到遇到结束的空字符。