Ask*_*aga 34 c struct c99 return-type return-value
尝试一些代码我意识到以下代码编译:
struct { int x, y; } foo(void) {
}
Run Code Online (Sandbox Code Playgroud)
好像我们正在定义一个foo返回匿名的函数struct.
现在,我的问题是:它是否只发生在使用我的编译器编译或者这是合法的C(99)?如果是这样,return语句的正确语法是什么?如何正确地将返回值赋给变量?
250*_*501 24
您返回的结构不是匿名结构.C标准将匿名结构定义为不使用标记的另一个结构的成员.你返回的是一个没有标签的结构,但由于它不是一个成员,它不是匿名的.Gcc使用名称<anonymous>来表示没有标记的结构.
假设你试图在函数中声明一个相同的结构.
struct { int x, y; } foo( void )
{
return ( struct { int x, y; } ){ 0 } ;
}
Run Code Online (Sandbox Code Playgroud)
gcc抱怨它:返回类型'struct <anonymous>'时出现不兼容的类型,但是'struct <anonymous>'是预期的
显然这些类型不兼容.看看标准,我们看到:
6.2.7兼容型和复合型
1:如果类型相同,则两种类型具有兼容类型.用于确定两种类型是否兼容的附加规则在6.7.2中描述了类型说明符,在6.7.3中描述了类型限定符,在6.7.6中描述了声明符.此外,如果它们的标记和成员满足以下要求,则在单独的转换单元中声明的两个结构,联合或枚举类型是兼容的:如果使用标记声明一个,则另一个应使用相同的标记声明.如果两者都在各自的翻译单元内的任何地方完成,则以下附加要求适用:其成员之间应存在一对一的对应关系,以便每对相应的成员都被宣布为兼容类型; 如果使用对齐说明符声明该对中的一个成员,则使用等效的对齐说明符声明另一个成员; 如果该对的一个成员使用名称声明,则另一个成员使用相同的名称声明.对于两个结构,相应的成员应按相同的顺序声明.对于两个结构或联合,相应的位域应具有相同的宽度.对于两个枚举,相应的成员应具有相同的值.
第二个粗体部分解释说,如果两个结构都没有标记,例如在这个例子中,它们必须遵循该部分之后列出的其他要求,他们这样做.但是如果你注意到它们必须在单独的翻译单元中的第一个粗体部分,那么示例中的结构不是.所以它们不兼容,代码无效.
不可能使代码正确,因为如果声明一个结构并在此函数中使用它,则必须使用一个标记,这违反了两个结构必须具有相同标记的规则:
struct t { int x, y; } ;
struct { int x, y; } foo( void )
{
struct t var = { 0 } ;
return var ;
}
Run Code Online (Sandbox Code Playgroud)
再次gcc抱怨:返回类型'struct t'时出现不兼容的类型,但是'struct <anonymous>'是预期的
小智 14
这适用于我的GCC版本,但似乎完全是黑客攻击.也许在自动生成的代码中很有用,你不想处理生成唯一结构标记的额外复杂性,但我甚至想要提出合理化.
struct { int x,y; }
foo(void) {
typeof(foo()) ret;
ret.x = 1;
ret.y = 10;
return ret;
}
main()
{
typeof(foo()) A;
A = foo();
printf("%d %d\n", A.x, A.y);
}
Run Code Online (Sandbox Code Playgroud)
此外,它依赖于编译器中存在的typeof() - GCC和LLVM似乎支持它,但我相信很多编译器都不支持它.
您可能无法从函数中显式地显示 return某些聚合值(除非您使用typeof扩展来获取结果的类型).
这个故事的寓意是,即使你能宣布一个回复匿名 的函数,struct你几乎 也不应该这样做.
而是命名struct和代码:
struct twoints_st { int x; int y; };
struct twoints_st foo (void) {
return ((struct twoints_st) {2, 3});
};
Run Code Online (Sandbox Code Playgroud)
请注意,它在语法上是正常的,但在执行时通常是未定义的行为,没有函数return(例如,您可以exit在其中调用).但是你为什么要编码(可能是合法的):
struct { int xx; int yy; } bizarrefoo(void) { exit(EXIT_FAILURE); }
Run Code Online (Sandbox Code Playgroud)