Ear*_*rlz 5 c parameters types function unions
我最近发现有些东西编译(不确定它是否合法).我需要这样的事情:我的项目输出选定拱门的机器代码(可能与运行程序的拱门相同或不同).所以,我想最多支持64位架构现在(同时也支持现有的32个和16位archs.)我目前的解决方案是NEW_STATE的"基地"以只是一个uint64_t中,并手动铸造16位和32位的需要.虽然,我发现你可以在函数参数中编译联合.所以这个函数编译:
int pcg_new_state(pcg_state *s,int arch,void *mem,int sz,
union{
uint16_t b16;
uint32_t b32;
uint64_t b64;
}base ,int self_running);
Run Code Online (Sandbox Code Playgroud)
虽然这种事情是"合法的"或者是否受到任何其他编译器的支持?而且,我无法弄清楚如何在不创建联合的情况下调用此函数,然后将此联合传递给new_state.
总结一下:是的,这在C 中是有效的,尽管在C++中是非法的.后者包含这个解释差异的说明
更改:在C++中,可能无法在返回或参数类型中定义类型.在C中,允许这些类型定义
例:
void f( struct S { int a; } arg ) {} // valid C, invalid C++
enum E { A, B, C } f() {} // valid C, invalid C++
Run Code Online (Sandbox Code Playgroud)
C中的结构等价是通过"类型兼容性"的概念来完成的.这允许C将许多类型视为相同,即使它们在理论上是不同的 - 因为它们在两个不同的转换单元中声明.在C++中,这个概念不存在,因为类型具有链接并且与同一实体匹配(即允许成员函数相互链接).
注意,上面引用的解释是基于C89,它在确定类型兼容性时没有考虑结构的标记名称.在C89草案中,相关文本如下:
此外,如果它们具有相同数量的成员,相同的成员名称和兼容的成员类型,则在单独的翻译单元中声明的两个结构,联合或枚举类型是兼容的.对于两个结构,成员的顺序应相同;
在C99中,类型检查更严格:如果一个结构具有标记名称,则另一个结构声明必须具有相同的标记名称.所以在你的未命名联合类型的情况下,要在另一个具有兼容类型的TU中声明一个函数,如果你想拥有有效的C99代码(没有未定义的行为),你将需要一个未命名的联合 - 你不能"欺骗",并且在一个TU中使用一个命名的union,在另一个TU中使用一个未命名的union.不过,在我看来,这个"技巧"对C89有效.C99 TC3 6.2.7/1:
此外,如果它们的标记和成员满足以下要求,则在单独的转换单元中声明的两个结构,联合或枚举类型是兼容的:如果使用标记声明一个,则另一个应使用相同的标记声明.如果两者都是完整类型,则以下附加要求适用:其成员之间应存在一对一的对应关系,使得每对相应成员都声明为具有兼容类型,并且如果相应对的一个成员是使用名称声明,另一个成员使用相同的名称声明.对于两个结构,相应的成员应按相同的顺序声明.
你想要的方式不起作用.调用函数会将参数转换为参数类型,就像通过正常赋值一样.
因此,要使其工作,您必须具有与参数类型兼容的参数.对于在同一翻译单元中声明的两个联合,这意味着它们的类型必须相等 - 这是您在同一翻译单元中提出兼容类型的唯一方法.但是这不起作用,因为未命名联合的声明创建了一个唯一的新类型 - 没有办法使用另一个声明"引用"它.
因此,总结一下 - 你必须给联合类型一个名字.为了避免创建一个单独的变量来传递所需的基本参数,我会在函数外部声明它,并创建函数来返回你可能传递的联合
union base_type {
uint16_t b16;
uint32_t b32;
uint64_t b64;
};
int pcg_new_state(pcg_state *s,int arch,void *mem,int sz,
union base_type base,int self_running);
union base_type base_b16(uint16_t t)
{ union base_type b; b.b16 = t; return b; }
union base_type base_b32(uint32_t t)
{ union base_type b; b.b32 = t; return b; }
union base_type base_b64(uint64_t t)
{ union base_type b; b.b64 = t; return b; }
Run Code Online (Sandbox Code Playgroud)
现在,它可能如下所示
pcg_new_state(...., base_b32(4211), ....);
Run Code Online (Sandbox Code Playgroud)