C 基于四个16位整数创建64位整数

C 基于四个16位整数创建64位整数,c,integer,bit-manipulation,64-bit,16-bit,C,Integer,Bit Manipulation,64 Bit,16 Bit,我正在尝试使用位运算符将C中的四个16位整数转换为一个64位整数(操作系统是运行Ubuntu20.04服务器的Linux)。我的总体目标是能够将四个32位整数转换为一个128位整数(来自in6\u addrstruct中四个32位整数的IPv6源IP地址)。然而,在下面的示例中,我使用了四个16位整数和一个64位整数,因为我在使用GCC分配128位整数时遇到了问题(我假设我可以将下面相同的逻辑应用到我的总体目标中) 在本例中,我的系统的字节顺序也是小端的。不过,如果您想在big endian上演

我正在尝试使用位运算符将C中的四个16位整数转换为一个64位整数(操作系统是运行Ubuntu20.04服务器的Linux)。我的总体目标是能够将四个32位整数转换为一个128位整数(来自
in6\u addr
struct中四个32位整数的IPv6源IP地址)。然而,在下面的示例中,我使用了四个16位整数和一个64位整数,因为我在使用GCC分配128位整数时遇到了问题(我假设我可以将下面相同的逻辑应用到我的总体目标中)

在本例中,我的系统的字节顺序也是小端的。不过,如果您想在big endian上演示如何执行此操作,请随意执行

以下是我目前使用C语言编写的测试代码:

#include <stdio.h>
#include <inttypes.h>

int main()
{
    uint16_t nums[4];
    uint64_t num = 2310051230312123321;
    uint64_t mainnum = 0;

    #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
        nums[0] = num >> 0;     // xxxx ---- ---- ----
        nums[1] = num >> 16;    // ---- ---- ---- xxxx
        nums[2] = num >> 32;    // ---- ---- xxxx ----
        nums[3] = num >> 48;    // ---- xxxx ---- ----
    #else
        /*
        nums[0] = num << 0;
        nums[1] = num << 16;
        nums[2] = num << 32;
        nums[3] = num << 48;
        */
    #endif

    printf("Num => %" PRIu64 "\nNum #1 => %" PRIu16 "\nNum #2 => %" PRIu16 "\nNum #3 => %" PRIu16 "\nNum #4 => %" PRIu16 "\n\n", num, nums[0], nums[1], nums[2], nums[3]);

    #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
        mainnum = ((uint64_t)(nums[0] >> 16 | nums[1]) >> 48) | (nums[3] << 16 | nums[2]);
    #else
        /* ... */
    #endif

    uint16_t other[4];

    other[0] = mainnum >> 0;
    other[1] = mainnum >> 16;
    other[2] = mainnum >> 32;
    other[3] = mainnum >> 48;

    printf("Num => %" PRIu64 "\nNum #1 => %" PRIu16 "\nNum #2 => %" PRIu16 "\nNum #3 => %" PRIu16 "\nNum #4 => %" PRIu16 "\n", mainnum, other[0], other[1], other[2], other[3]);

    return 0;
}
我希望
num
mainnum
相同

我知道我不理解这里的某些东西,而且我对位运算符没有太多经验

mainnum = ((uint64_t)(nums[0] >> 16 | nums[1]) >> 48) | (nums[3] << 16 | nums[2]);

mainnum=((uint64_t)(nums[0]>>16 | nums[1])>>48)(nums[3]您需要与创建
nums
from
num
相同/相应的索引和移位量:

nums[0] = num >> 0;                 // xxxx ---- ---- ----
nums[1] = num >> 16;                // ---- ---- ---- xxxx
nums[2] = num >> 32;                // ---- ---- xxxx ----
nums[3] = num >> 48;                // ---- xxxx ---- ----
而且,每个术语都需要一个
(uint64_t)
强制转换以强制升级到64位。否则,移位将超过赋值右侧中间术语的大小(例如,它们将使用
int
和/或
无符号int


mainnum |=(uint64_t)nums[0]此外,我相信您的大多数问题都来自您需要强制转换
nums[I]的事实
在对其进行任何算术运算之前将数字转换为
uint64\t
。生成
mainnum
是不对的。索引错误,方向移位错误。在移位之前将每个元素强制转换为64位。使用
的左移位将位从高位移动到低位。16位整数的右移位为16位完全丢弃所有位,产生零。要将四个16位整数组合成64位整数,需要将其中三个左移16、32和48位。移位时,将要移位的操作数转换为所需的结果类型。例如,
nums[3]使用移位操作通常是在您希望代码独立于尾数的情况下完成的。如果您希望不同的尾数有不同的行为,那么
memcpy
union
是一个简单得多的选择谢谢您!这非常有效,一旦我开始深入研究逐位操作,我以后也会记住这一点口粮等。
nums[0] = num >> 0;                 // xxxx ---- ---- ----
nums[1] = num >> 16;                // ---- ---- ---- xxxx
nums[2] = num >> 32;                // ---- ---- xxxx ----
nums[3] = num >> 48;                // ---- xxxx ---- ----
mainnum |= (uint64_t) nums[0] << 0;
mainnum |= (uint64_t) nums[1] << 16;
mainnum |= (uint64_t) nums[2] << 32;
mainnum |= (uint64_t) nums[3] << 48;
mainnum =
    (uint64_t) nums[0] << 0 |
    (uint64_t) nums[1] << 16 |
    (uint64_t) nums[2] << 32 |
    (uint64_t) nums[3] << 48;