我有一个如下联盟:
typedef unsigned long GT_U32;
typedef unsigned short GT_U16;
typedef unsigned char GT_U8;
typedef union
{
GT_U8 c[8];
GT_U16 s[4];
GT_U32 l[2];
} GT_U64;
我想将此联盟转换为以下内容:
typedef unsigned long long int UINT64;
我写的演员函数如下:
UINT64 gtu64_to_uint64_cast(GT_U64 number_u)
{
UINT64 casted_number = 0;
casted_number = number_u.l[0];
casted_number = casted_number << 32;
casted_number = casted_number | number_u.l[1];
return casted_number;
}
此函数使用l
成员执行移位和按位或。如果联盟的s
或c
成员用于设置其值,会发生什么?
我不确定此函数是否总是正确地转换值。我怀疑它与long
和short
的字节顺序有关。任何人都可以帮忙吗?
下面列出了完整的示例程序。
#include <stdio.h>
typedef unsigned long GT_U32;
typedef unsigned short GT_U16;
typedef unsigned char GT_U8;
typedef union
{
GT_U8 c[8];
GT_U16 s[4];
GT_U32 l[2];
} GT_U64;
typedef unsigned long long int UINT64;
UINT64 gtu64_to_uint64_cast(GT_U64 number_u)
{
UINT64 casted_number = 0;
casted_number = number_u.l[0];
casted_number = casted_number << 32;
casted_number = casted_number | number_u.l[1];
return casted_number;
}
int main()
{
UINT64 left;
GT_U64 right;
right.s[0] = 0x00;
right.s[1] = 0x00;
right.s[2] = 0x00;
right.s[3] = 0x01;
left = gtu64_to_uint64_cast(right);
printf ("%llu\n", left);
return 0;
}
答案 0 :(得分:1)
这真的很丑陋且依赖于实现 - 只需使用memcpy,例如
UINT64 gtu64_to_uint64_cast(GT_U64 number_u)
{
UINT64 casted_number;
assert(sizeof(casted_number) == sizeof(number_u));
memcpy(&casted_number, &number_u, sizeof(number_u));
return casted_number;
}
答案 1 :(得分:1)
首先,请使用“stdint.h”中的typedef
来达到这个目的。你有很多关于整数类型宽度的假设,不要这样做。
如果s或c成员会发生什么 联盟用来设置它 值?
如果存在填充字节或填充位,则读取已通过其他成员写入的联合的成员可能会导致未定义的行为。唯一的例外是unsigned char
,它可能总是用于访问各个字节。因此通过c
访问很好。通过s
访问可能(在非常不可能的情况下)导致未定义的行为。
在你的情况下,没有像“正确”演员这样的事情。它只取决于你想如何将一个小数字数组解释为一个大数字。对此任务的一种可能的解释是你给出的那个。
答案 2 :(得分:1)
此代码应独立于填充,字节序,联合访问和隐式整数提升。
uint64_t gtu64_to_uint64_cast (const GT_U64* number_u)
{
uint64_t casted_number = 0;
uint8_t i;
for(i=0; i<8; i++)
{
casted_number |= (uint64_t) number_u->c[i] << i*8U;
}
return casted_number;
}
答案 3 :(得分:1)
如果你不能改变union的声明来包含一个显式的64位字段,也许你可以将它包装起来?像这样:
UINT64 convert(const GT_U64 *value)
{
union {
GT_U64 in;
UINT64 out;
} tmp;
tmp.in = *value;
return tmp.out;
}
这个确实违反了规则,即你只能从上次写入的工会成员中读取,所以也许它会让你的头发着火。我认为这样会很安全,不要看到像这样的联盟会包含填充但当然我可能错了。
我主要想包括这个,因为你不能改变“输入”联合的声明并不意味着你不能通过包装来做几乎相同的事情。
答案 4 :(得分:0)
可能更简单的方法是使用一个长长的成员:
typedef unsigned long long int UINT64;
typedef unsigned long GT_U32;
typedef unsigned short GT_U16;
typedef unsigned char GT_U8;
typedef union
{
GT_U8 c[8];
GT_U16 s[4];
GT_U32 l[2];
UINT64 ll;
} GT_U64;
然后,只需访问ll
即可获得64位值,而无需进行显式转换。您需要告诉编译器使用单字节struct
打包。
答案 5 :(得分:0)
您没有指定“正确投射值”的含义。
此代码将以最简单的方式进行转换,但它会根据您的系统字节顺序给出不同的结果。
UINT64 gtu64_to_uint64_cast(GT_U64 number_u) {
assert(sizeof(UINT64) == sizeof(GT_U64));
return *(UINT64 *) &number_u;
}