gpt4 book ai didi

c - GCC vs Clang 复制结构灵活数组成员

转载 作者:太空狗 更新时间:2023-10-29 15:39:57 26 4
gpt4 key购买 nike

考虑以下代码片段。

#include <stdio.h>

typedef struct s {
int _;
char str[];
} s;
s first = { 0, "abcd" };

int main(int argc, const char **argv) {
s second = first;
printf("%s\n%s\n", first.str, second.str);
}

当我用 GCC 7.2 编译它时,我得到:

$ gcc-7 -o tmp tmp.c && ./tmp
abcd
abcd

但是当我用 Clang(Apple LLVM 版本 8.0.0 (clang-800.0.42.1))编译它时,我得到以下信息:

$ clang -o tmp tmp.c && ./tmp
abcd
# Nothing here

为什么编译器的输出不同?我希望该字符串不会被复制,因为它是一个灵活的数组成员(类似于 this question )。为什么 GCC 实际复制它?

编辑

一些评论和回答表明这可能是由于优化。 GCC 可能使 second 成为 first 的别名,因此更新 second 应该不允许 GCC 进行该优化。我添加了这一行:

second._ = 1;

但这不会改变输出。

最佳答案

这是关于 gcc 发生的事情的真正答案。 second正如您所期望的那样,分配在堆栈上。它不是 first 的别名.这很容易通过打印他们的地址来验证。

此外,声明s second = first;正在破坏堆栈,因为 (a) gcc 正在为 second 分配最小存储量但是 (b) 它正在复制 first所有第二,破坏堆栈。

这是原始代码的修改版本,显示了这一点:

#include <stdio.h>

typedef struct s {
int _;
char str[];
} s;
s first = { 0, "abcdefgh" };
int main(int argc, const char **argv) {
char v[] = "xxxxxxxx";
s second = first;
printf("%p %p %p\n", (void *) v, (void *) &first, (void *) &second);
printf("<%s> <%s> <%s>\n", v, first.str, second.str);
}

在我的 32 位 Linux 机器上,使用 gcc,我得到以下输出:

0xbf89a303 0x804a020 0xbf89a2fc
<defgh> <abcdefgh> <abcdefgh>

从地址可以看出,vsecond在堆栈上,first在数据部分。此外,很明显 second 的初始化已覆盖 v在堆栈上,结果不是预期的 <xxxxxxxx> ,而是显示 <defgh> .

这对我来说似乎是一个 gcc 错误。至少,它应该警告 second 的初始化会破坏堆栈,因为它显然有足够的信息在编译时知道这一点。

编辑:我对此进行了更多测试,并通过拆分 second 的声明获得了基本相同的结果进入:

s second;
second = first;

真正的问题是作业。它正在复制 first所有 ,而不是结构类型的最小公共(public)部分,这是我认为它应该做的。事实上,如果你移动first的静态初始化到一个单独的文件中,作业完成了它应该做的,v打印正确,second.str是未定义的垃圾。这是 gcc 应该产生的行为,无论 first 是否初始化。是否在同一个编译单元可见。

关于c - GCC vs Clang 复制结构灵活数组成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46802747/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com