typedef struct test{
char c_arr[1];
} test;
test array[1] = {{1}};
test get(int index){
return array[index];
}
int main(){
char* a = get(0).c_arr;
return *a;
}
字符串
在这篇文章中,我们用C++解释了这种行为:在结构体中插入数组会导致clang警告
以上代码在使用gcc
或clang
编译时不会导致任何警告或错误。get(0).c_arr
是否返回一个指向临时变量的指针,该变量在表达式的末尾被销毁?如果是,是否解引用并返回其值UB?如果是,那么什么是修复它的好方法,也许是这样?
test* get(int index){
return &array[index];
}
型
2条答案
按热度按时间epfja78i1#
字符串
显然是UB;在
return
运行时,a
所引用的内存已经从堆栈中释放出来,如果出现相反的结果,我会非常恼火。想象一下,如果有人这样写:型
堆栈的浪费是很糟糕的,嵌入式程序员和内核程序员会为此大吵大闹。
然而,以下在C中是有效的:
char a = get(0).c_arr[0];
这是因为临时的持久性足够长,可以在表达式中使用。dsf9zpds2#
是的,这是未定义的行为。C17标准的相关章节是“6.2.4对象的存储时间”:
一个对象的 * 生命周期 * 是程序执行的一部分,在这段时间内,存储器被保证为它保留。一个对象存在,有一个恒定的地址,33)并在整个生命周期内保留它最后存储的值。34)如果一个对象在它的生命周期之外被引用,那么这个行为是未定义的。
具有结构或联合类型的非左值表达式,其中结构或联合包含具有数组类型的成员(包括递归地,所有包含的结构和联合的成员)引用具有自动存储持续时间和 * 临时生存期 * 的对象。它的生存期从表达式被求值时开始,并且它的初始值是表达式的值。完整的表达结束。
表达式
get(0)
不是左值,并且struct test
包含c_arr
,一个数组类型的成员,所以它有临时生命周期。这意味着return *a;
是UB,因为它在生命周期之外访问它。另外,这是不允许的一个重要提示是,如果你使用
char c;
而不是char c_arr[1];
,那么char* a = &get(0).c;
将是一个编译时错误,因为你不能接受右值的地址,你写的东西基本上在道德上等同于试图这样做。我提交了GCC bug 101358和LLVM issue #50346关于没有收到警告。