我最近遇到过这个discussion,其中返回的struct的数组成员直接传递给另一个函数并导致崩溃。
基本上,我们有一个函数返回类型为struct S
的对象(包含一个数组),并使用该对象的数组元素调用另一个函数:
#include <stdio.h>
#include <stdlib.h>
struct S
{
char array[10];
};
struct S func (void)
{
struct S s;
s.array[0] = 'H';
s.array[1] = 'e';
s.array[2] = 'l';
s.array[3] = 'l';
s.array[4] = 'o';
s.array[5] = '\0';
return s;
}
int main (int argc, char ** argv)
{
printf("%s\n", func().array);
return EXIT_SUCCESS;
}
虽然在上面提到的discussion中指出问题在于在下一个序列点之后访问func()
的调用结果,但我不清楚为什么以下后续工作没有在我的机器上崩溃:
#include <stdio.h>
#include <stdlib.h>
struct S
{
char array[10];
};
struct S func (void)
{
struct S s;
s.array[0] = 'H';
s.array[1] = 'e';
s.array[2] = 'l';
s.array[3] = 'l';
s.array[4] = 'o';
s.array[5] = '\0';
return s;
}
int main (int argc, char ** argv)
{
printf("%s\n", &func().array[0]);
return EXIT_SUCCESS;
}
与第一个示例(导致警告format '%s' expects argument of type 'char *', but argument 2 has type 'char[10]' [-Wformat=]
)相反,第二个示例编译没有任何问题 - 但无论如何,在下一个序列之后访问func()
调用的结果因此,根据上述讨论,这应该是未定义的行为。
所以我想知道在没有崩溃的情况下在我的机器上运行的第二个示例是否只是运气,或者是否还有另一个点在这里发挥作用 - 也许我理解为什么第一个崩溃是错误的,以及什么有在此answer中描述的另一个相关讨论在这里更具相关性。
编辑(澄清可能重复的内容):
我知道this answer (1),我也从相关讨论中读过this answer (2)。 但是,我认为两者都涉及与我打开的主题相对应的不同方面:(1)讨论由于在下一个序列点之后访问函数的结果而导致的未定义行为,(2)讨论由于具有数组而导致的未定义行为值类型(与左值类型相反)。
因此,虽然示例一是未定义的行为,但主要关注的是示例二: 如前所述,这可以在我的机器上运行而不会崩溃。我完全清楚这个事实并不是任何未定义行为的荒谬的证据 - 但是,至少值得考虑在这种情况下未定义行为的谬误。 此外,我不知道(1)中接受的答案如何回答我关于将(2)中提到的要点纳入本期问题的问题:知道在我的第二个例子中是否指向使用char而不是数组类型实际上对语言规则有任何不同。
无论如何,我认为我的第二个例子也违反了(1)和(2)中提到的两个约束,但是对此的其他意见将不胜感激。