gpt4 book ai didi

c - 未定义的行为 : when attempting to access the result of function call

转载 作者:太空狗 更新时间:2023-10-29 16:58:56 25 4
gpt4 key购买 nike

以下编译并打印“string”作为输出。

#include <stdio.h>

struct S { int x; char c[7]; };

struct S bar() {
struct S s = {42, "string"};
return s;
}

int main()
{
printf("%s", bar().c);
}

显然这似乎调用了一个未定义的行为

C99 6.5.2.2/5 If an attempt is made to modify the result of a function call or to access it after the next sequence point, the behavior is undefined.

我不明白它在哪里说“下一个序列点”。这是怎么回事?

最佳答案

您遇到了语言的一个微妙角落。

在大多数上下文中,数组类型的表达式隐式转换为指向数组对象第一个元素的指针。此处均不适用的异常(exception)情况是:

  • 当数组表达式是一元&运算符的操作数时(产生整个数组的地址);
  • 当它是一元 sizeof 或(自 C11 起) _Alignof 运算符时(sizeof arr产生数组的大小,而不是指针的大小);和
  • 当它是用于初始化数组对象的初始化程序中的字符串文字时(char str[6] = "hello"; 不会将 "hello" 转换为一个 char*.)

(N1570草案错误地将_Alignof添加到异常(exception)列表中。事实上,由于不明确的原因,_Alignof只能应用于一个类型名称,而不是表达式。)

请注意,这里有一个隐含的假设:数组表达式首先引用一个数组对象。在大多数情况下,它确实如此(最简单的情况是数组表达式是声明的数组对象的名称)——但在这种情况下,没有数组对象

如果函数返回一个结构,则结构结果按值返回。在这种情况下,结构包含一个数组,给我们一个数组 value,但至少在逻辑上没有对应的数组 object。所以数组表达式 bar().c 衰减为指向第一个元素的指针......呃,嗯,......一个不存在的数组对象。

2011 ISO C 标准通过引入“临时生命周期”解决了这个问题,它仅适用于“具有结构或 union 类型的非左值表达式,其中结构或 union 包含一个数组类型的成员”(N1570 6.2.4p8)。这样的对象可能不会被修改,并且它的生命周期在包含完整表达式或完整声明符的末尾结束。

从 C2011 开始,您的程序行为已明确定义。 printf 调用获取指向数组第一个元素的指针,该数组是具有临时生命周期的结构对象的一部分;该对象将继续存在,直到 printf 调用完成。

但从 C99 开始,行为是未定义的——不一定是因为你引用的子句(据我所知,没有中间序列点),而是因为 C99 没有定义数组对象是 printf 工作所必需的。

如果您的目标是让这个程序运行,而不是理解它为什么会失败,您可以将函数调用的结果存储在一个显式对象中:

const struct s result = bar();
printf("%s", result.c);

现在您有一个具有自动而不是临时存储持续时间的结构对象,因此它在 printf 执行期间和之后存在> 打电话。

关于c - 未定义的行为 : when attempting to access the result of function call,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13755628/

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