64位编译器中的Memcpy问题

时间:2014-08-07 04:21:17

标签: c

对于初学者,我的主要目标是在64位环境中将unsigned long转换为unsigned int(并且在没有任何编译警告的情况下执行此操作)。这可以通过此功能轻松完成:

unsigned int a_to_b(unsigned long a)
{
     return((unsigned int)(a));
}

虽然它给出了正确的结果,但问题是在64位环境中它会在编译时抛出警告:

  

1506-742(I)64位可移植性:通过将unsigned long int类型转换为unsigned int类型可能导致数字丢失。

要绕过此警告,我们尝试了此功能:

unsigned int a_to_b(unsigned long a)
{
    unsigned int b;
    int skip = sizeof(unsigned long) - sizeof(unsigned int);
    memcpy(&b, (&a)+skip, sizeof(b));
    return(b);
}

现在这并没有在编译时发出任何警告,但它没有给出正确的输出。 我在32位编译器中尝试了相同的代码,它工作正常。

请建议如何纠正memcpy的这种行为或绕过警告的任何其他方式。

2 个答案:

答案 0 :(得分:2)

#include <limits.h>

unsigned int a_to_b(unsigned long a)
{
     return(a & UINT_MAX);
}

在Mac OS X 10.9.4上传递,GCC 4.9.1设置为非常繁琐:

gcc -O3 -g -std=c11 -Wall -Wextra -Werror -c cvt.c

我无法在AIX上测试(或者是HP-UX?)。


如评论中所述:

  

我真的不喜欢这个主意,但有一种可能性是:

union
{
    unsigned long ul;
    unsigned int ui[2];
} u;
     

并将参数分配给u.ul并返回u.ui[0]u.ui[1](可能是后者,因为AIX运行在大端的Power芯片上,至少在默认情况下是这样)。这是一个骗子。编译器可能足以发现“误用”,但可能不会。

充实为半便携式代码:

unsigned int a_to_b(unsigned long a)
{
    const unsigned long byteorder = 0xFF;
    const int LOW_ORDER_4_BYTES = (*(char *)&byteorder == 0); 
    union
    {
        unsigned long ul;
        unsigned int  ui[2];
    } u;
    u.ul = a;
    return(u.ui[LOW_ORDER_4_BYTES]);
}

在小端机器上测试,它给出了正确的结果。我认为它应该会自动检测大端机器并在那里给出正确的结果,但我还是无法验证。

完整的测试代码:

#include <stdio.h>

unsigned int a_to_b(unsigned long a);

unsigned int a_to_b(unsigned long a)
{
    const unsigned long byteorder = 0xFF;
    const int LOW_ORDER_4_BYTES = (*(char *)&byteorder == 0); 
    union
    {
        unsigned long ul;
        unsigned int ui[2];
    } u;
    u.ul = a;
    return(u.ui[LOW_ORDER_4_BYTES]);
}

int main(void)
{
    unsigned long x = 0xFEDCBA9876543210ULL;
    printf("0x%.8X\n", a_to_b(x));
    return 0;
}

输出:

0x76543210

答案 1 :(得分:0)

不要这样做,可能导致特定机器中的陷阱表示。

你的电脑是小端的。你应该这样写:

unsigned int a_to_b(unsigned long a)
{
    unsigned int b;
    memcpy(&b, &a, sizeof(b));
    return(b);
}

Big and Little Endian