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

我有一个计数寄存器,它由两个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?

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

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

 #include  #include  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 (uint64_t) mostSignificantWord << 32 | leastSignificantWord

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

    (uint64_t)0x00000001 - > 0x0000000000000001

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

    0x0000000000000001 << 32 - > 0x0000000100000000

离开逻辑转变

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

    0b0101 | 0b1001 - > 0b1101

我的看法:

 unsigned int low =  unsigned int high =  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 =  unsigned int high =  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的变化时,我永远不会确定。

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

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

我经常以hex打印,而不是尝试打印小数。

因此……

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

或者,根据架构,平台和编译器,有时你可以逃脱…

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

要么

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

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

希望这可以帮助。

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

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

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

在游戏的后期,但我需要这样的东西类似于代表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