pro*_*rsn 17 c printf types casting void-pointers
我%p在Stack Overflow中已经阅读了很多关于C语言中格式说明符用法的答案,但似乎没有一个解释为什么void*所有类型都需要显式转换为char*.
我当然知道这样一个事实,即强制转换的要求void*与使用可变函数(参见本答案的第一条评论)有关,而非强制性要求.
这是一个例子:
int i;
printf ("%p", &i);
Run Code Online (Sandbox Code Playgroud)
产生关于类型不兼容性的警告,并且&i应该进行铸造void*(根据标准的要求,再次参见此处).
虽然这一大块代码能够顺利编译,但没有关于类型转换的任何投诉:
char * m = "Hello";
printf ("%p", m);
Run Code Online (Sandbox Code Playgroud)
如何char*从这一要求中"解脱"?
PS:可能值得补充的是我在 x86_64架构上工作,因为指针类型大小依赖于它,并且使用 gcc作为linux上的-W -Wall -std=c11 -pedantic编译器和编译选项.
Sou*_*osh 20
类型的参数不需要显式转换char*,因为char *具有相同的表示和对齐要求void *.
引用C11,第6.2.5章
指向void的指针应具有与指向字符类型的指针相同的表示和对齐要求.(48) [...]
和脚注48)
相同的表示和对齐要求意味着可互换性作为函数的参数,函数的返回值和联合的成员.
C11标准6.2.5/28说:
指向void的指针应具有与指向字符类型的指针相同的表示和对齐要求.48)
脚注48是:
相同的表示和对齐要求意味着可互换性作为函数的参数,函数的返回值和联合的成员.
但7.21.6.1("fprintf函数")说%p:
参数应该是指向void的指针.
这显然是一个矛盾.在我看来,一个明智的解释是说6.2.5/28的意图是,void *并且char *实际上可以互换为函数参数的类型,它们与原型不对应.(即非原型函数的参数,或匹配可变函数原型的省略号).
显然,您正在使用的编译器采用类似的视图.
为了支持这一点,7.21.6.1中的参数类型的规范,如果按照字面意思而不考虑意图,在实践中有很多其他的不一致性(例如,它说printf("%lx", -1);明确定义,但是printf("%u", 1);未定义的行为) ).
提出此要求的原因是 C 标准允许对不同类型的指针使用不同的表示形式,但有 2 个值得注意的约束:
voidand charorunsigned char及其限定版本的指针应具有相同的表示形式。因此,在某些体系结构上,int *和char *可能具有不同的表示形式,例如不同的大小,并且它们可以以不同的方式传递给可变参数函数,从而导致int i = 1; printf("%p", &i);和int i = 1; printf("%p", (void*)&i);表现不同。
但请注意,Posix 标准要求所有指针类型具有相同的大小和表示形式。因此,在 Posix 系统上printf("%p", &i);应该按预期运行。