Как объединить два 32-разрядных целых числа в одно 64-разрядное целое число? - PullRequest
21 голосов
/ 05 мая 2010

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

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

В частности:

leastSignificantWord = 4294967295; //2^32-1

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

Это напечатало бы отлично.

Когда число увеличивается до 4294967296, у меня оно так, что наименьшее значение для Windows стирается до 0, а значение MostSignificantWord (изначально 0) теперь равно 1. Теперь весь счетчик должен читать 4294967296, но сейчас он просто читает 10, потому что Я просто объединяю 1 из наиболее значимых слов и 0 из наименьших значимых слов.

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

Ответы [ 8 ]

60 голосов
/ 05 мая 2010

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

#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

left logical shift

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

    0b0101 | 0b1001 -> 0b1101

33 голосов
/ 05 мая 2010
long long val = (long long) mostSignificantWord << 32 | leastSignificantWord;
printf( "%lli", val );
3 голосов
/ 05 мая 2010

мой дубль:

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 или 32улл. Что-то, в чем я не уверен, когда вижу сдвиги с константами больше 31.

1 голос
/ 12 апреля 2012

Этот код работает, когда верхний и нижний 32 отрицательны:

data64 = ((LONGLONG)upper32<< 32) | ((LONGLONG)lower32& 0xffffffff);
1 голос
/ 05 мая 2010

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

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

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

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

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

или

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

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

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

0 голосов
/ 20 июня 2019

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

#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 голосов
/ 21 декабря 2017

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

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

0 голосов
/ 19 октября 2012

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...