Подтвердить что ты не робот

Как объединить два 32-разрядных целых числа в одно 64-битное целое число?

У меня есть регистр счетчика, который состоит из двух 32-разрядных целых без знака, один для более высоких 32 бит значения (наиболее значимое слово), а другой для младших 32 бит значения (наименее значимое слово).

Каков наилучший способ в C объединить эти два 32-разрядных целых числа без знака, а затем отобразить их как большое число?

В частности:

leastSignificantWord = 4294967295; //2^32-1

printf("Counter: %u%u", mostSignificantWord,leastSignificantWord);

Это будет хорошо печататься.

Когда число увеличивается до 4294967296, у меня есть его так, чтобы наименьшее значение SignificantWord стиралось до 0, а mostSignificantWord (0 изначально) теперь равно 1. Теперь весь счетчик должен читать 4294967296, но сейчас он просто читает 10, m просто конкатенация 1 из mostSignificantWord и 0 из минимумSignificantWord.

Как мне отобразить 4294967296 вместо 10?

4b9b3361

Ответ 1

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

Ответ 2

В этом случае может быть полезно использовать целые числа без знака с явными размерами:

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

left logical shift

  • | делает 'побитовый или' (логическое ИЛИ на битах операндов).

    0b0101 | 0b1001 → 0b1101

Ответ 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).

Вторая версия не работает с объектами большого числа, но от нее требуется угадать, если константа 32 должна быть 32 или 32ull. Что-то я не уверен, когда вижу сдвиги с константами больше 31.

Ответ 4

Вместо того, чтобы пытаться печатать десятичные числа, я часто печатаю в шестнадцатеричном формате.

Таким образом...

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

В качестве альтернативы, в зависимости от архитектуры, платформы и компилятора, иногда вы можете уйти с чем-то вроде...

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

или

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

Однако этот альтернативный метод очень зависит от машины (endian-ness, а также 64 против 32 бит,...) и вообще не рекомендуется.

Надеюсь, что это поможет.

Ответ 5

Этот код работает, когда и upper32, и lower32 отрицательны:

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

Ответ 6

Есть еще один способ использования массивов и указателей:

#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

Вы можете сделать это, записав 32-битные значения в нужные места в памяти:

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

Это зависит от машины, однако, например, он не будет работать корректно на процессорах большого числа.

Ответ 8

Поздно в игре, но мне нужна была такая вещь, которая была бы похожа на цифровую строку base10 из 64-битного целого числа на 32-битном встроенном env..

Итак, воодушевленный http://mathforum.org/library/drmath/view/55970.html Я написал этот код, который может делать то, что задается в вопросе, но не ограничивает его base10: can конвертировать в любую базу от 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