如何将两个32位整数组合成一个64位整数?

时间:2021-05-26 12:00:46

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时,我有它,所以最少有意思的W擦除为0,而且最重要的字(最初为0)现在为1.整个计数器现在应该读为4294967296,但是现在它只读取10,因为我只是连接1个来自最重要的词,0个来自最不重要的词。

How should I make it display 4294967296 instead of 10?

我怎么能让它显示4294967296而不是10?

7 个解决方案

#1


32  

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

#2


54  

It might be advantageous to use unsigned integers with explicit sizes 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;
}
Output

4294967296

4294967296

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

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

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

    (uint64_t) 0x00000001 -> 0x0000000000000001

    (uint64_t)0x00000001 - > 0x0000000000000001

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

    < <做左移。在c中,无符号整数的左移执行逻辑移位。< p>

    0x0000000000000001 << 32 -> 0x0000000100000000

    0x0000000000000001 << 32 - > 0x0000000100000000

如何将两个32位整数组合成一个64位整数?

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

    | '按位或'(操作数位的逻辑或)。

    0b0101 | 0b1001 -> 0b1101

    0b0101 | 0b1001 - > 0b1101

#3


3  

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目标,但是如果常量32应该是32或32ull,则它需要猜测工作。当我看到常数大于31的变化时,我永远不会确定。

#4


1  

This code works when both upper32 and lower32 is negative:

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

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

#5


0  

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.

但是,这种替代方法非常依赖于机器(endian-ness,以及64 vs 32 bit,......),一般不推荐使用。

Hope this helps.

希望这可以帮助。

#6


0  

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.

这与机器有关,但是,例如它在大端处理器上无法正常工作。

#7


-1  

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.html I 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

#1


32  

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

#2


54  

It might be advantageous to use unsigned integers with explicit sizes 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;
}
Output

4294967296

4294967296

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

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

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

    (uint64_t) 0x00000001 -> 0x0000000000000001

    (uint64_t)0x00000001 - > 0x0000000000000001

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

    < <做左移。在c中,无符号整数的左移执行逻辑移位。< p>

    0x0000000000000001 << 32 -> 0x0000000100000000

    0x0000000000000001 << 32 - > 0x0000000100000000

如何将两个32位整数组合成一个64位整数?

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

    | '按位或'(操作数位的逻辑或)。

    0b0101 | 0b1001 -> 0b1101

    0b0101 | 0b1001 - > 0b1101

#3


3  

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目标,但是如果常量32应该是32或32ull,则它需要猜测工作。当我看到常数大于31的变化时,我永远不会确定。

#4


1  

This code works when both upper32 and lower32 is negative:

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

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

#5


0  

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.

但是,这种替代方法非常依赖于机器(endian-ness,以及64 vs 32 bit,......),一般不推荐使用。

Hope this helps.

希望这可以帮助。

#6


0  

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.

这与机器有关,但是,例如它在大端处理器上无法正常工作。

#7


-1  

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.html I 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