2つの32ビット符号なし整数で構成されるカウントレジスタがあります。1つは値の上位32ビット(最上位ワード)用で、もう1つは値の下位32ビット(最下位ワード)用です。
Cでこれらの2つの32ビット符号なし整数を組み合わせて大きな数として表示する最良の方法は何ですか?
具体的には:
leastSignificantWord = 4294967295; //2^32-1
printf("Counter: %u%u", mostSignificantWord,leastSignificantWord);
これはうまく印刷されます。
数値が4294967296にインクリメントされると、最小署名数ワードが0にワイプし、最大署名数(最初は0)が1になったので、カウンター全体が4294967296を読み取る必要がありますが、今は単に10を読み取ります。 mostSignificantWordから1、およびleastSignificantWordから0。
10ではなく4294967296と表示するにはどうすればよいですか?
long long val = (long long) mostSignificantWord << 32 | leastSignificantWord;
printf( "%lli", val );
この場合、unsigned整数をexplicitサイズで使用すると有利な場合があります:
#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-> 0x0000000000000001
<<
は 左シフト を行います。 Cでは、符号なし整数の左シフトは 論理シフト を実行します。
0x0000000000000001 << 32-> 0x0000000100000000
|
は 'bitwise or' (論理値ORオペランドのビット))を実行します。
0b0101 | 0b1001-> 0b1101
私の見解:
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を最適化します)。
2番目のバージョンはビッグエンディアンターゲットでは機能しませんが、定数32が32または32ullである場合は、推測作業が不要になります。 31を超える定数のシフトを見ると、確信が持てません。
このコードは、upper32とlower32の両方が負の場合に機能します。
data64 = ((LONGLONG)upper32<< 32) | ((LONGLONG)lower32& 0xffffffff);
10進数を印刷する代わりに、16進数で印刷することがよくあります。
したがって...
printf ("0x%x%08x\n", upper32, lower32);
または、アーキテクチャ、プラットフォーム、コンパイラーによっては、次のようなものを回避できる場合があります...
printf ("%lld\n", lower32, upper32);
または
printf ("%lld\n", upper32, lower32);
ただし、この代替方法はマシンに非常に依存するため(エンディアン、64ビットと32ビットなど)、一般的には推奨されません。
お役に立てれば。
配列とポインタを使用する別の方法があります:
#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;
}