32비트 정수 두 개를 64비트 정수 한 개로 합치는 방법은?
카운트 레지스터가 있습니다. 카운트 레지스터는 두 개의 32비트 부호 없는 정수로 구성되어 있습니다. 하나는 값의 상위 32비트(가장 중요한 단어), 다른 하나는 값의 하위 32비트(가장 중요한 단어)로 구성되어 있습니다.
C에서 이 두 개의 32비트 부호 없는 정수를 결합한 후 큰 숫자로 표시하는 가장 좋은 방법은 무엇입니까?
구체적으로:
leastSignificantWord = 4294967295; //2^32-1
printf("Counter: %u%u", mostSignificantWord,leastSignificantWord);
이것은 인쇄가 잘 될 것입니다.
숫자가 4294967296으로 늘어나면 가장 의미 없는 단어가 0으로 지워지고 가장 의미 있는 단어(처음에는 0)가 1이 됩니다.이제 카운터 전체가 4294967296을 읽어야 하지만 지금은 10을 읽습니다. 왜냐하면 저는 가장 중요한 단어에서 1을 연결하고 가장 중요하지 않은 단어에서 0을 연결하고 있기 때문입니다.
10개가 아니라 4294967296으로 표시되도록 하려면 어떻게 해야 합니까?
이 경우 명시적 크기의 부호 없는 정수를 사용하는 것이 유리할 수 있습니다.
#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;
}
Output
4294967296
와해.(uint64_t) mostSignificantWord << 32 | leastSignificantWord
(typename)는 C로 타이핑을 합니다.값 데이터 유형을 다음으로 변경합니다.typename.(unint64_t) 0x00000001 -> 0x000000000001
<<왼쪽 시프트를 합니다.C에서 부호 없는 정수의 왼쪽 시프트는 논리 시프트를 수행합니다.0x00000000000001 << 32 -> 0x0000000100000000
![]()
|bitwise or 를 수행합니다(피연산자의 비트에 논리 OR).0b0101 | 0b1001 -> 0b1101
long long val = (long long) mostSignificantWord << 32 | leastSignificantWord;
printf( "%lli", val );
나의 의견:
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 */
두 버전 모두 작동하며 성능이 비슷합니다(컴파일러는 메모리를 최적화합니다).
두 번째 버전은 빅 엔디언 타겟에서는 작동하지 않지만 상수 32가 32 또는 32ull이어야 할 경우 추측 작업을 제거합니다.상수가 31보다 큰 변화를 볼 때 확실하지 않은 것.
배열과 포인터를 사용하는 또 다른 방법이 있습니다.
#include <stdio.h>
#include <inttypes.h>
int main(void) {
// Two uint32_t to one uint64_t
uint32_t val1[2] = {1000, 90000};
uint64_t *val1_u64_ptr = (uint64_t*)val1; //intermediate pointer cast to avoid Wstrict-aliasing warnings
uint64_t val2 = *val1_u64_ptr;
printf("val2: %" PRIu64 "\n", val2);
// val2: 386547056641000
// back to uint32_t array from uint64_t
uint64_t val3 = 386547056641000ull;
uint32_t *val4 = (uint32_t*)&val3;
printf("val4: %" PRIu32 ", %" PRIu32 "\n", val4[0], val4[1]);
// val4: 1000, 90000
return 0;
}
이 코드는 저에게 훨씬 이해하기 쉽고 읽기 쉽습니다.당신은 단지 메모리에 두개로 연속적인 공간을 만들고 있을 뿐입니다.32-bit unsigned int그리고 이 같은 메모리 공간은 하나로 읽힙니다.64-bit unsigned int가치와 그 반대의 versa.다른 유형으로 읽히는 메모리만 관련된 작업이 없습니다.
편집
당신이 이미 그것을 가지고 있다면 이것은 훌륭하다는 것을 언급하는 것을 잊었습니다.64-bit array어디선가 읽었을 때 당신은 모든 것을 쉽게 읽을 수 있었습니다.32-bit array쌍:
#include <stdio.h>
#include <inttypes.h>
int main() {
uint64_t array64[] = {
386547056641000ull,
93929935171414ull,
186655006591110ull,
73141496240875ull,
161460097995400ull,
351282298325439ull,
97310615654411ull,
104561732955680ull,
383587691986172ull,
386547056641000ull
};
int n_items = sizeof(array64) / sizeof(array64[0]);
uint32_t* array32 = (uint32_t*)&array64;
for (int ii = 0; ii < n_items * 2; ii += 2) {
printf("[%" PRIu32 ", %" PRIu32 "]\n", array32[ii], array32[ii + 1]);
}
return 0;
}
출력:
[1000, 90000]
[3295375190, 21869]
[22874246, 43459]
[2498157291, 17029]
[3687404168, 37592]
[1218152895, 81789]
[3836596235, 22656]
[754134560, 24345]
[4162780412, 89310]
[1000, 90000]
유니언 구조 사용
https://stackoverflow.com/a/2810339/2548351 의 구조 조합을 사용하는 것이 더 좋고 더 읽기 쉽습니다.
#include <stdio.h>
#include <inttypes.h>
typedef union {
int64_t big;
struct {
int32_t x;
int32_t y;
};
} xy_t;
int main() {
// initialize from 64-bit
xy_t value = {386547056641000ull};
printf("[%" PRIu32 ",%" PRIu32 "]\n", value.x, value.y);
// [1000, 90000]
// initialize as two 32-bit
xy_t value2 = {.x = 1000, .y = 90000};
printf("%" PRIu64, value.big);
// 386547056641000
return 0;
}
십진 인쇄를 시도하는 대신 종종 16진수로 인쇄합니다.
그래서...
printf ("0x%x%08x\n", upper32, lower32);
또는 아키텍처, 플랫폼 및 컴파일러에 따라 때때로 다음과 같은 작업을 수행할 수도 있습니다.
printf ("%lld\n", lower32, upper32);
아니면
printf ("%lld\n", upper32, lower32);
그러나 이 대체 방법은 시스템에 매우 의존적이며(엔디안니스 뿐만 아니라 64 대 32 비트, ...) 일반적으로 권장되지 않습니다.
도움이 되길 바랍니다.
이 코드는 상위 32와 하위 32가 모두 음수일 때 작동합니다.
data64 = ((LONGLONG)upper32<< 32) | ((LONGLONG)lower32& 0xffffffff);
32비트 값을 메모리의 올바른 위치에 기록하면 됩니다.
unsigned long int data64;
data64=lowerword
*(&((unsigned int)data64)+1)=upperword;
그러나 이것은 기계에 의존적입니다. 예를 들어 빅 엔디언 프로세서에서는 제대로 작동하지 않습니다.
게임이 늦었지만 32비트 임베디드 환경에서 64비트 정수의 숫자 베이스10 문자열을 표현하는 것과 비슷한 것이 필요했습니다.
그래서 저는 링크에서 영감을 받아 질문에서 질문한 것을 할 수 있지만, 베이스 10에 제한을 두지 않는 이 코드를 썼습니다: 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);
당신의 버프는 4294967296을 포함할 것입니다.
언급URL : https://stackoverflow.com/questions/2768890/how-to-combine-two-32-bit-integers-into-one-64-bit-integer
'codememo' 카테고리의 다른 글
| Angular-ui bootstrap datepicker에서 week column and button 제거 (0) | 2023.10.10 |
|---|---|
| 지원되지 않는 메서드: BaseConfig.getApplicationIdSuffix() (0) | 2023.10.10 |
| :hover(마우스 탈퇴 시)와 반대되는 것은 무엇입니까? (0) | 2023.10.10 |
| 브라우저 스택 자동화에서 트랙터 테스트 실행 (0) | 2023.10.10 |
| XMLHttpRequest는 응답에 오류 상태가 있는 경우에도 항상 "load" 이벤트 수신기를 호출합니다. (0) | 2023.10.10 |