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

时间:2010-05-04 20:49:29

标签: c printf

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

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

具体来说:

leastSignificantWord = 4294967295; //2^32-1

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

这样打印就好了。

当数字增加到4294967296时,我有它,所以最少有意义的W擦除为0,而且最重要的字(最初为0)现在为1.整个计数器现在应该读为4294967296,但是现在它只读取10,因为我'我只是从最重要的词汇中加入1,从最不重要的词汇中加入0。

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

8 个答案:

答案 0 :(得分:59)

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

#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

细分(uint64_t) mostSignificantWord << 32 | leastSignificantWord

  • (typename)在C中执行typecasting。它将值数据类型更改为typename

    (uint64_t)0x00000001 - &gt; 0x0000000000000001

  • <<执行left shift。在C中,无符号整数的左移执行logical shift

    0x0000000000000001&lt;&lt; 32 - &gt; 0x0000000100000000

left logical shift

  • |执行'bitwise or'(操作数位的逻辑OR)。

    0b0101 | 0b1001 - &gt; 0b1101

答案 1 :(得分:33)

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

答案 2 :(得分:3)

我的看法:

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 */

另一种方法:

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 */

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

第二个版本不适用于big-endian目标,但是如果常量32应该是32或32ull,则它需要猜测工作。当我看到常数大于31的变化时,我无法确定。

答案 3 :(得分:1)

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

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

答案 4 :(得分:0)

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

因此......

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

或者,根据架构,平台和编译器的不同,有时您可以使用类似的东西......

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

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

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

希望这有帮助。

答案 5 :(得分:0)

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

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

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

答案 6 :(得分:0)

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

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

答案 7 :(得分:-1)

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

所以,受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;
        }
    }
}

如果你要求

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

你的buff将包含4294967296