如果我们将整数指针指向字符数组的开头并取消对它的引用,会发生什么? #包括 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); }

如果我们将整数指针指向字符数组的开头并取消对它的引用,会发生什么? #包括 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尝试

我可以了解此代码输出的解释吗?

此代码的行为不由C标准定义,因为在
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);
}