memcpy返回值赋值给int指针后用%s输出为何合法?
#include <stdio.h> #include <string.h> //Compiler version gcc 6.3.0 int main() { char a1[20] ={0} , a2[20] ={0}; int *ptr; fgets(a1,20,stdin); fgets(a2,20,stdin); ptr = memcpy(a1,a2,strlen(a2)-1); printf("%s \n",ptr); if(ptr) printf("%s",a1); return 0; }
核心解答
你所说的“printf("%s",ptr);完全合法”是认知误区:这个写法在主流平台能跑出预期结果只是巧合,从C语言标准层面属于未定义行为,具体拆解如下:
编译无报错的原因
printf是可变参数函数,...对应的可变参数默认不会被编译器做严格类型校验,只有开启-Wformat等高警告等级时,编译器才会对格式串和参数的类型匹配做扩展校验。memcpy返回void*类型,C标准允许void*隐式转换为任意对象指针类型,所以将返回值赋值给int*类型的ptr本身是合法操作,不会触发编译错误。
运行时能正常输出的原因
memcpy返回的是目标缓冲区的首地址,也就是字符数组a1的起始地址,因此ptr存储的地址值和a1完全一致。在x86、ARM等绝大多数通用架构上,所有类型指针的底层存储都是纯内存地址,没有类型区分,所以printf处理%s格式符时,会直接按这个地址逐字节读取直到遇到\0终止符,输出效果和传入char*类型的a1没有区别。
为什么说这个写法不符合标准
C标准明确规定%s格式符对应的参数必须是指向\0结尾字符序列的char*类型指针,传入其他类型指针属于未定义行为:
- 开启
-Wall -Wformat编译参数时,GCC、Clang等编译器会直接抛出format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int *’的警告。 - 在指针带类型标识、不同类型指针内存表示不同的特殊架构上,这段代码会直接崩溃或输出乱码。
内容的提问来源于stack exchange,提问作者Prince
相关产品推荐
相关产品推荐

