2011-02-15 233 views
0

我有一个工会如下:联盟为unsigned long long int类型投

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构件进行变速和按位或。如果工会的sc成员用于设置其值,会发生什么情况?

我不确定这个函数是否总能正确地转换值。我怀疑它与longshort的字节顺序有关。任何身体可以帮助吗?

下面列出了完整的示例程序。

#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

这一个如果访问你的数组的mem areya ..“right.l [3] = 0x01;” – eaanon01 2011-02-15 13:44:43

+1

代码错了,没有l [3]。应该是,我想。 – Serkan 2011-02-15 13:48:22

+0

纠正了这一点。 – 2011-02-15 13:48:22

回答

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; 
} 
+0

memcpy()同样丑陋且依赖于实现。结构/联合可以在其内部的任何位置填充字节。我没有看到assert()对于填充是比assert()更好还是更差。 – Lundin 2011-02-15 13:54:42

+0

@Lundin:如果联盟存在任何填充/对齐问题,那么所有投注都无效 - 将联合投射到64位int永远不会完全可靠。使用上述解决方案的好处是,它至少不会遭受排序问题,并且有些面向未来。你能提出更好的解决方案吗? – 2011-02-15 13:58:26

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打包。

0

您不指定“正确投射值”的含义。

此代码将以最简单的方式投射,但根据您的系统字典顺序,它会给出不同的结果。

所有的
UINT64 gtu64_to_uint64_cast(GT_U64 number_u) { 
    assert(sizeof(UINT64) == sizeof(GT_U64)); 
    return *(UINT64 *) &number_u; 
} 
1

首先,请使用从 “stdint.h的” typedef S代表这样一个目的。你有很多关于整数类型宽度的假设,不要那样做。

如果S或C成员工会 用于设置其 值会发生什么?

如果存在填充字节或填充位,读取通过另一个成员写入的联合的成员可能会导致未定义的行为。唯一的例外是unsigned char,它可能总是用于访问单个字节。所以通过c访问很好。通过s访问可能会(在极不可能的情况下)导致未定义的行为。

在你的情况下,没有像“正确”投射那样的东西。这取决于你想如何将一个小数字数组解释为一个大数字。对于这个任务的一种可能的解释是你给的那个。

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; 
} 
1

如果你无法改变工会的声明,包括一个明确的64位字段,也许你可以把它包装?就像这样:

UINT64 convert(const GT_U64 *value) 
{ 
    union { 
    GT_U64 in; 
    UINT64 out; 
    } tmp; 

    tmp.in = *value; 
    return tmp.out; 
} 

确实违反,说你只能从最后写入工会会员阅读,所以也许它会设置你的头发着火的规则。我认为这将是相当安全的,虽然没有看到像这样的工会会包括填充的情况,但我当然可能是错的。

我主要想包括这一点,因为你不能改变“输入”联合声明并不意味着你不能通过包装它来做几乎相同的事情。

相关问题