相同的C代码,在Mac和Linux上的输出不同

tv6aics1  于 11个月前  发布在  Mac
关注(0)|答案(2)|浏览(106)

我在运行下面的代码时,把指针和const弄得一团糟:

int main()
{
    const int test = 10;
    int *ptr = &test;
    printf("%d\n", test);
    *ptr = 1;
    printf("%d\n", test);
}

字符串
在Mac上,结果是:

10
10


在Linux机器上:

10
1


为什么值的改变在Mac上不起作用?两台机器都用gcc编译代码。

1tuwyuhd

1tuwyuhd1#

您可以在Godbolt的编译器资源管理器https://godbolt.org/z/5xfEqj9x1上运行测试
从输出窗格中可以看出,行为与您的观察结果一致,以下是一些解释:

  • 代码有未定义的行为:你将test定义为一个const int局部变量,但你通过将其地址存储到一个int *指针并通过*ptr = 1设置值来显式地绕过它。两个编译器都会发出关于这个可疑赋值的警告,代码*ptr = 1具有未定义的行为,因为您正在修改const变量。如果test是在全局范围内定义的,(或使用static限定符)这个赋值可能触发了一个分段错误。在这种情况下,变量的间接修改,如果执行的话,没有任何效果,因为编译器可能会假设test变量没有改变。
  • macOS上的gcc默认是clang的别名,它生成的代码与Linux上的gcc不同。即使没有优化,clang假设const变量在两个printf语句之间没有被修改,并将10作为参数值传递gcc使用**-O2或更高的优化级别执行此操作,但读取-O 0**处的变量值,为Linux上的第二个printf调用生成1

执行具有未定义行为的代码意味着任何事情都可能发生,不同的输出是一个常见的例子,这是令人沮丧的,因为环境并不像分段错误那样明确地指出问题。* 任何事情都可能发生 * 不是字面上的意思,它意味着可能发生不可预测的副作用或缺乏副作用,包括看不到任何东西,读取不同的值,出现了一个分段错误......意料之外的事。
为了尽量减少此类问题,请始终在编译时添加所有有用的警告并修复其原因(例如:-Wall -Wextra -Werror)。

nwsw7zdq

nwsw7zdq2#

您忽略了来自编译器的诊断消息,并在Mac和Linux上使用不同的工具和/或不同的开关进行构建。
int * ptr = &test;中的初始化违反了C 2018(C标准的2018版本)中的约束6.5.16.1 1,因为它将int *值分配给const int *类型的对象,而这些类型是不兼容的,并且不包含在允许的情况下。需要符合的编译器发出诊断消息。
尽管违反了约束,编译器仍然可以接受代码,但是C标准没有定义这种行为。您的一个编译器将ptr视为指向可以更改和存储新值的对象,并打印更改后的值。另一个编译器观察到您的程序正在使用可以假定不会更改的const int,因此,在优化期间,它使用原始值而不是改变的值。

脚注

1这是一个初始化,初始化规则参考赋值规则。

相关问题