如果我们将整数指针指向字符数组的开头并取消对它的引用,会发生什么? #包括 int main() { 字符s[]=“ABCD EFGH”; int*x=&s[0]; printf(“%d%d\n”,*x,x); x=s; printf(“%d%d\n”,*x,x); printf(“%d%d%d\n”、&s[0]、s和&s); }
我可以了解此代码输出的解释吗?此代码的行为不由C标准定义,因为在如果我们将整数指针指向字符数组的开头并取消对它的引用,会发生什么? #包括 int main() { 字符s[]=“ABCD EFGH”; int*x=&s[0]; printf(“%d%d\n”,*x,x); x=s; printf(“%d%d\n”,*x,x); printf(“%d%d%d\n”、&s[0]、s和&s); },c,C,我可以了解此代码输出的解释吗?此代码的行为不由C标准定义,因为在int*x=&s[0]之后使用*x违反了C标准中的规则。C 2018 6.5 7规定: 对象的存储值只能由具有以下类型之一的左值表达式访问: -与对象的有效类型兼容的类型 -与对象的有效类型兼容的类型的限定版本 -与对象的有效类型相对应的有符号或无符号类型 -一种类型,它是与对象的有效类型的限定版本相对应的有符号或无符号类型 -在其成员中包含上述类型之一的聚合或联合类型(递归地包括子聚合或包含的联合的成员),或 -字符类型 *x尝试
int*x=&s[0]之后使用*x
代码>违反了C标准中的规则。C 2018 6.5 7规定:
对象的存储值只能由具有以下类型之一的左值表达式访问:
-与对象的有效类型兼容的类型
-与对象的有效类型兼容的类型的限定版本
-与对象的有效类型相对应的有符号或无符号类型
-一种类型,它是与对象的有效类型的限定版本相对应的有符号或无符号类型
-在其成员中包含上述类型之一的聚合或联合类型(递归地包括子聚合或包含的联合的成员),或
-字符类型
*x
尝试访问s
的字节,就像它们是int
对象一样。然而,该存储器的有效类型是char(C 2018 6.5 6:“访问其存储值的对象的有效类型是该对象的声明类型,如果有的话……”)。因此:
int
与有效类型char
不兼容
int
不是与char
兼容的类型的限定版本
int
不是与char
对应的有符号或无符号类型
int
不是与合格版本的char
相对应的有符号或无符号类型
int
不是任何类型的聚合或联合类型
int
不是字符类型
违反此要求意味着未根据C 2018 4 2对行为进行定义:
如果违反了出现在约束或运行时约束之外的“应”或“不应”要求,则行为未定义
由于该行为未被C标准定义,编译器可以选择定义他们将如何使用它,也可以不定义他们将如何使用它。在后一种情况下,编译器的优化可能导致程序产生令人惊讶的结果。在前一种情况下,编译器的一种常见行为是通过将它指向的字节重新解释为int
类型来计算*x
,前提是地址与int
对象适当对齐。(GCC和Clang允许使用命令行开关-fno strict aliasing
)
也就是说,如果&s[0]
是一个允许在C实现中开始int
的地址,那么*x
将从&s[0]
开始的字节中生成一个int
值。如果C实现使用ASCII,则s
的前四个字节是4116、4216、4316和4416。然后,如果int
是四个八位字节,以小尾数存储(在较低的地址具有较低的有效字节),并且s
可接受地对齐int
,则*x
的值将为4443424116,十进制为1145258561
总之,获得此结果需要大量依赖于实现的行为:
s
适合于int
对象
- C实现支持使用
int
对char
对象进行别名处理
- C实现使用ASCII和八位字节
int
是C实现中的四个字节
- C实现以小尾端顺序存储
int
对象
好吧,除了使用%p
格式和相应的void*
参数来打印指针外,其他任何方法都是未定义的…@Jarod42:没有隐式转换?@skrrt-Yup,是的。@Jarod42它会的compile@P__JsupportswomeninPoland被标记为C++…语言不同:)
#include <stdio.h>
int main()
{
char s[]="ABCD EFGH";
int *x=&s[0];
printf("%d %d\n", *x, x);
x=s;
printf("%d %d\n", *x, x);
printf("%d %d %d\n", &s[0], s, &s);
}