为何这段C代码未触发段错误?printf无终止符却正常输出?
#include <stdio.h> void print(char* c) { printf("%s\n", c); //Uses %s to print a string } int main() { char a = 'd'; print(&a); return 0; }
问题
上述C代码中,char变量a无空终止符,将其地址传入使用printf("%s")的print函数后,未触发段错误,且仅输出'd'就停止。请问:为何这段代码未触发段错误?GCC是否将其转换为字符串字面量?无空终止符时printf如何停止输出?这属于正常行为吗?
为何未触发段错误?
段错误只会在程序访问无权访问的内存区域时触发。这里printf从&a的地址开始读取字节,刚好在a的下一个内存位置读到了值为0的字节(空终止符),没有越界到非法内存范围,所以没触发段错误。这完全是巧合——取决于a在栈上的布局,以及后续内存的内容。如果a后面的内存不是0,printf会一直读取垃圾数据,直到碰到0或者访问到非法内存才崩溃。GCC是否将其转换为字符串字面量?
没有。char a = 'd';是在栈上分配的单个局部字符变量,和存储在只读数据段的字符串字面量完全是两回事。查看汇编代码就能验证:a存储在当前函数的栈帧中,传递给print的是栈内存地址,和数据段无关。无空终止符时printf如何停止输出?
printf("%s")的逻辑是从传入的地址开始逐个读取字节,直到碰到值为\0(ASCII码0)的字节才停止。你的代码里刚好a后面的内存字节是0,所以只输出了'd'就停止。如果后续内存不是0,它会持续输出内存中的垃圾数据,直到遇到\0或者触发内存访问错误。这属于正常行为吗?
这不是定义良好的正常行为,而是未定义行为。C标准明确要求,使用%s格式符时,传入的指针必须指向以空字符终止的字符串。你的代码违反了这个规则,程序的行为完全不可预测——这次碰巧输出'd'就停,下次可能输出乱码,甚至直接崩溃。编译器和运行环境没有义务为这种情况提供稳定的结果。
内容的提问来源于stack exchange,提问作者adsf

