web-dev-qa-db-ja.com

2つの32ビット整数を1つの64ビット整数に組み合わせる方法は?

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と表示するにはどうすればよいですか?

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

この場合、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

left logical shift

  • |'bitwise or' (論理値ORオペランドのビット))を実行します。

    0b0101 | 0b1001-> 0b1101

61
jfs

私の見解:

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を超える定数のシフトを見ると、確信が持てません。

3

このコードは、upper32とlower32の両方が負の場合に機能します。

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

10進数を印刷する代わりに、16進数で印刷することがよくあります。

したがって...

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

または、アーキテクチャ、プラットフォーム、コンパイラーによっては、次のようなものを回避できる場合があります...

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

または

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

ただし、この代替方法はマシンに非常に依存するため(エンディアン、64ビットと32ビットなど)、一般的には推奨されません。

お役に立てれば。

1
Sparky

配列とポインタを使用する別の方法があります:

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