表达式"str"的类型是char[4]。(在 C++ 中,它会是const char[4].)
在大多数情况下,任何数组类型的表达式都会隐式转换为指向数组对象第一个元素的指针。这种转换通常被称为“衰减”。例外情况是:
- 当它是一元运算符的操作数时
sizeof(sizeof "str"产生数组的大小,而不是指针的大小)。
- 当它是一元运算符的操作数时
&(&"str"产生 type 的结果char(*)[4], not char*)。
- 当它是用于初始化数组对象的初始化程序中的字符串文字时(此处不适用)。
在这三种情况下,数组表达式保持其数组类型。
字符串文字是指隐式创建的具有静态存储持续时间的数组对象,其大小足以容纳文字的字符加上终止的'\0'空字符。在这种情况下,"str"指的是类型为 的匿名静态对象char[4]。
所以:
printf("%p\n", "str");
"str"被隐式转换为一个char*值,指向's'的"str"。
printf("%p\n", &"str"[0]);
如上所述"str", in"str"[0]衰减char*为 。 "str"[0"产生一个char*值,指向's'. 所以"str"和"str"[0]具有相同的类型和价值。
printf("%p\n", &"str");
在这里,由于"str"是 的操作数&,因此不会发生衰减,因此&"str"产生匿名char[4]对象的地址,而不是其第一个字符的地址。这个表达式的类型是char(*)[4],或“指向 4 个字符数组的指针”。
表达式&"str"[0]和&"str"两者都产生指针值,它们都指向内存中的同一位置,但它们的类型不同。
在所有三种情况下,计算表达式的结果都作为参数传递给printf. printf使用"%p"格式需要类型的参数void*。在前两种情况下,您传递了 achar*和语言的要求,char*并void*暗示它将按预期工作。char*在第三种情况下, vs.没有这样的规则char(*)[4],所以
printf("%p\n", &"str");
未定义。
碰巧的是,在大多数实现中,所有指针类型都具有相同的大小和表示形式,因此您可以将任意类型的指针传递给printfwith "%p"。
在所有三种情况下,您可以(并且可能应该)将表达式显式转换为void*,避免未定义的行为:
printf("%p\n", (void*)"str");
printf("%p\n", (void*)&"str"[0]);
printf("%p\n", (void*)&"str");
您问题的第二部分涉及一个不同的问题;它是关于指向函数的指针。指针类型表达式的规则与数组类型的规则类似:函数类型的表达式(例如函数名)被隐式转换为指向函数的指针,除非它是sizeof(这是非法的) 或&(这会产生函数的地址)。这就是为什么应用*or&到一个函数就像一个无操作一样。在*func中,func首先衰减为指向函数的指针,*解除对指针的引用,结果再次衰减为指向函数的指针。在&func中,&抑制了衰减,但它产生了指向函数func本身会产生的相同指针。