C语言 如何将两个 32 位整数合并为一个 64 位整数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2768890/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 05:22:21  来源:igfitidea点击:

How to combine two 32-bit integers into one 64-bit integer?

cprintf

提问by jiake

I have a count register, which is made up of two 32-bit unsigned integers, one for the higher 32 bits of the value (most significant word), and other for the lower 32 bits of the value (least significant word).

我有一个计数寄存器,它由两个 32 位无符号整数组成,一个用于值的高 32 位(最高有效字),另一个用于值的低 32 位(最低有效字)。

What is the best way in C to combine these two 32-bit unsigned integers and then display as a large number?

在 C 中组合这两个 32 位无符号整数然后显示为大数的最佳方法是什么?

In specific:

具体来说:

leastSignificantWord = 4294967295; //2^32-1

printf("Counter: %u%u", mostSignificantWord,leastSignificantWord);

This would print fine.

这会打印得很好。

When the number is incremented to 4294967296, I have it so the leastSignificantWord wipes to 0, and mostSignificantWord (0 initially) is now 1. The whole counter should now read 4294967296, but right now it just reads 10, because I'm just concatenating 1 from mostSignificantWord and 0 from leastSignificantWord.

当数字增加到 4294967296 时,我得到了它,所以 leastSignificantWord 擦除为 0,而 mostSignificantWord(最初为 0)现在是 1。整个计数器现在应该读取 4294967296,但现在它只读取 10,因为我只是连接1 来自mostSignificantWord 和0 来自leastSignificantWord。

How should I make it display 4294967296 instead of 10?

我应该如何让它显示 4294967296 而不是 10?

回答by jfs

It might be advantageous to use unsignedintegers with explicitsizes in this case:

在这种情况下,使用具有显式大小的无符号整数可能是有利的 :

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

int main(void) {
  uint32_t leastSignificantWord = 0;
  uint32_t mostSignificantWord = 1;
  uint64_t i = (uint64_t) mostSignificantWord << 32 | leastSignificantWord;
  printf("%" PRIu64 "\n", i);

  return 0;
}
输出

4294967296

4294967296

Break down of (uint64_t) mostSignificantWord << 32 | leastSignificantWord

分解的 (uint64_t) mostSignificantWord << 32 | leastSignificantWord

  • (typename)does typecastingin C. It changes value data type to typename.

    (uint64_t) 0x00000001 -> 0x0000000000000001

  • <<does left shift. In C left shift on unsigned integers performs logical shift.

    0x0000000000000001 << 32 -> 0x0000000100000000

  • (typename)在 C中进行类型转换。它将值数据类型更改为typename.

    (uint64_t) 0x00000001 -> 0x0000000000000001

  • <<左移。在 C 中,无符号整数的左移执行逻辑移位

    0x0000000000000001 << 32 -> 0x0000000100000000

left logical shift

逻辑左移

  • |does 'bitwise or'(logical OR on bits of the operands).

    0b0101 | 0b1001 -> 0b1101

  • |执行“按位或”(操作数位上的逻辑或)。

    0b0101 | 0b1001 -> 0b1101

回答by twk

long long val = (long long) mostSignificantWord << 32 | leastSignificantWord;
printf( "%lli", val );

回答by Nils Pipenbrinck

my take:

我的看法:

unsigned int low = <SOME-32-BIT-CONSTRANT>
unsigned int high = <SOME-32-BIT-CONSTANT>

unsigned long long data64;

data64 = (unsigned long long) high << 32 | low;

printf ("%llx\n", data64); /* hexadecimal output */
printf ("%lld\n", data64); /* decimal output */

Another approach:

另一种方法:

unsigned int low = <SOME-32-BIT-CONSTRANT>
unsigned int high = <SOME-32-BIT-CONSTANT>

unsigned long long data64;
unsigned char * ptr = (unsigned char *) &data;

memcpy (ptr+0, &low, 4);
memcpy (ptr+4, &high, 4);

printf ("%llx\n", data64); /* hexadecimal output */
printf ("%lld\n", data64); /* decimal output */

Both versions work, and they will have similar performance (the compiler will optimize the memcpy away).

两个版本都可以工作,并且它们将具有相似的性能(编译器将优化 memcpy)。

The second version does not work with big-endian targets but otoh it takes the guess-work away if the constant 32 should be 32 or 32ull. Something I'm never sure when I see shifts with constants greater than 31.

第二个版本不适用于 big-endian 目标,但是如果常量 3​​2 应该是 32 或 32ull,它会消除猜测。当我看到常数大于 31 的变化时,我永远不确定。

回答by Sparky

Instead of attempting to print decimal, I often print in hex.

我经常以十六进制打印,而不是尝试打印十进制。

Thus ...

因此 ...

printf ("0x%x%08x\n", upper32, lower32);

Alternatively, depending upon the architecture, platform and compiler, sometimes you can get away with something like ...

或者,根据体系结构、平台和编译器,有时您可以使用类似...

printf ("%lld\n", lower32, upper32);

or

或者

printf ("%lld\n", upper32, lower32);

However, this alternative method is very machine dependent (endian-ness, as well as 64 vs 32 bit, ...) and in general is not recommended.

但是,这种替代方法非常依赖机器(字节序,以及 64 位和 32 位,...),一般不推荐使用。

Hope this helps.

希望这可以帮助。

回答by caiohamamura

There's another way using arrays and pointers:

还有另一种使用数组和指针的方法:

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

int main(void) {
    uint32_t val1[2] = {1000, 90000};
    uint64_t *val2 = (uint64_t*)val1;
    printf("val2 %llu\n", *val2);

    // back to uint32_t from uint64_t
    uint32_t *val3 = (uint32_t*)val2;
    printf("val3: %u, %u\n", val3[0], val3[1]);

    return 0;
}

回答by AIMrus

This code works when both upper32 and lower32 is negative:

当 upper32 和 lower32 均为负数时,此代码有效:

data64 = ((LONGLONG)upper32<< 32) | ((LONGLONG)lower32& 0xffffffff);

回答by mohit

You could do it by writing the 32-bit values to the right locations in memory:

您可以通过将 32 位值写入内存中的正确位置来实现:

unsigned long int data64;
data64=lowerword
*(&((unsigned int)data64)+1)=upperword;

This is machine-dependent however, for example it won't work correctly on big-endian processors.

然而,这取决于机器,例如它不能在大端处理器上正常工作。

回答by tmx976

Late at the game, but I needed such a thing similar to represent a numerical base10 string of a 64bit integer on a 32bit embedded env..

在游戏后期,但我需要类似的东西来表示 32 位嵌入式环境上的 64 位整数的数字 base10 字符串。

So, inspired by http://mathforum.org/library/drmath/view/55970.htmlI wrote this code that can do what asked in the question, but not limiting on base10: can convert to any base from 2 to 10, and can be easly extended to base N.

因此,受http://mathforum.org/library/drmath/view/55970.html 的启发,我编写了这段代码,可以执行问题中提出的问题,但不限制 base10:可以转换为 2 到 10 的任何基数,并且可以很容易地扩展到基数 N。

void stringBaseAdd(char *buf, unsigned long add, int base){

    char tmp[65], *p, *q;
    int l=strlen(buf);
    int da1, da2, dar;
    int r;

    tmp[64]=0;
    q=&tmp[64];
    p=&buf[l-1];
    r=0;
    while(add && p>=buf){

        da1=add%base;
        add/=base;
        da2=*p-'0';
        dar=da1+da2+r;

        r=(dar>=base)? dar/base: 0;
        *p='0'+(dar%base);
        --p;
    }

    while(add){

        da1=add%base;
        add/=base;
        dar=da1+r;

        r=(dar>=base)? dar/base: 0;
        --q;
        *q='0'+(dar%base);
    }

    while(p>=buf && r){

        da2=*p-'0';
        dar=da2+r;

        r=(dar>=base)? 1: 0;
        *p='0'+(dar%base);
        --p;
    }

    if(r){

        --q;
        *q='0'+r;
    }

    l=strlen(q);
    if(l){

        memmove(&buf[l], buf, strlen(buf)+1);
        memcpy(buf, q, l);
    }
}
void stringBaseDouble(char *buf, int base){

    char *p;
    int l=strlen(buf);
    int da1, dar;
    int r;

    p=&buf[l-1];
    r=0;
    while(p>=buf){

        da1=*p-'0';
        dar=(da1<<1)+r;

        r=(dar>=base)? 1: 0;
        *p='0'+(dar%base);
        --p;
    }

    if(r){

        memmove(&buf[1], buf, strlen(buf)+1);
        *buf='1';
    }
}
void stringBaseInc(char *buf, int base){

    char *p;
    int l=strlen(buf);
    int da1, dar;
    int r;

    p=&buf[l-1];
    r=1;
    while(p>=buf && r){

        da1=*p-'0';
        dar=da1+r;

        r=(dar>=base)? 1: 0;
        *p='0'+(dar%base);
        --p;
    }

    if(r){

        memmove(&buf[1], buf, strlen(buf)+1);
        *buf='1';
    }
}
void stringLongLongInt(char *buf, unsigned long h, unsigned long l, int base){

    unsigned long init=l;
    int s=0, comb=0;

    if(h){

        comb=1;
        init=h;
        while(!(init&0x80000000L)){

            init<<=1;
            init|=(l&0x80000000L)? 1: 0;
            l<<=1;
            s++;
        }
    }

    buf[0]='0';
    buf[1]=0;
    stringBaseAdd(buf, init, base);

    if(comb){

        l>>=s;
        h=0x80000000L>>s;
        s=sizeof(l)*8-s;
        while(s--){

            stringBaseDouble(buf, base);
            if(l&h)
                stringBaseInc(buf, base);

            h>>=1;
        }
    }
}

If you ask for

如果你要求

char buff[20];
stringLongLongInt(buff, 1, 0, 10);

your buff will contain 4294967296

你的 buff 将包含 4294967296