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