Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Из двух 32bit слепить 64bit


Автор: alex7851 20.8.2012, 14:59
Задача такая. Есть два 32 битных беззнаковых целых, нужно сделать из них одно 64 битное за наименьшее число тактов, не прибегая ко всяким там сдвигам и сложениям.
На ум пришло:
Код

    unsigned int a=0x90abcdef, b=0x12345678;
    unsigned __int64 c;

    *( (unsigned int*)&c + 0 ) = b;
    *( (unsigned int*)&c + 1 ) = a;

Битхак со всеми вытекающими (gcc с желанным ключем -o3 это компилирует неверно). Мб еще как-нибудь можно? Хотя сомневаюсь.
Заранее спасибо.

Автор: casey 20.8.2012, 15:26
Код

union
{
    
    struct 
    {
        unsigned int a;
        unsigned int b;
    } _2uint32;
    
    unsigned __int64 c;

} my_union;

my_union._2uint32.a=0x90abcdef;
my_union._2uint32.b=0x12345678;

my_union.c; //  <-----------


хотя в принципе это то же самое

Автор: alex7851 20.8.2012, 16:17
Спасибо.
Цитата(casey @ 20.8.2012,  15:26)
хотя в принципе это то же самое

Ну, -o3 вдруг заработал, так что, что ваш код "законнее".

Автор: leniviy 20.8.2012, 21:11
Цитата(alex7851 @  20.8.2012,  14:59 Найти цитируемый пост)
не прибегая ко всяким там сдвигам и сложениям.

Это единственный законный способ. А ваш вариант с кастованием в указатель будет работать не на всех архитектурах
http://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D1%80%D1%8F%D0%B4%D0%BE%D0%BA_%D0%B1%D0%B0%D0%B9%D1%82%D0%BE%D0%B2#.D0.92.D0.B0.D1.80.D0.B8.D0.B0.D0.BD.D1.82.D1.8B_.D0.B7.D0.B0.D0.BF.D0.B8.D1.81.D0.B8

Автор: Randajad 20.8.2012, 21:17
Это называется strict aliasing, поэтому ваш код не работает. smile

To casey:
Не то же самое, это полностью валидный код. smile

А чем сдвиги не устраивают? С 99% вероятностью они будут оптимизированы и выкинуты из кода.

P.S.
Код

union
{
    
    struct 
    {
        unsigned int a;
        unsigned int b;
    };
    
    unsigned __int64 c;
} my_union;

my_union.a = ...;
my_union.b = ...;


Код

union
{
    
     unsigned int arr[2];
    
    unsigned __int64 c;
} my_union;

my_union.arr[0] = ...;
my_union.arr[1] = ...;


Код

unsigned __int64 i = ...;
i |= (__int64)... << 32;

Автор: leniviy 20.8.2012, 21:24
предлагаю протестировать производительность 

Автор: bsa 26.8.2012, 15:48
Цитата(Randajad @  20.8.2012,  22:17 Найти цитируемый пост)
С 99% вероятностью они будут оптимизированы и выкинуты из кода.

к сожалению, gcc с 99% вероятностью это не делает.

Автор: Randajad 28.8.2012, 19:59
Какая разрядность? 32? Там нет регистров в 64 бита, так что юзать сдвиги он не сможет. А на x64 сдвиги быстрее доступа к памяти.

Автор: leniviy 28.8.2012, 20:32
Цитата(Randajad @  28.8.2012,  19:59 Найти цитируемый пост)
так что юзать сдвиги он не сможет

Но оператор << все равно скомпилируется в рабочий код

Автор: bsa 28.8.2012, 23:22
Цитата(Randajad @  28.8.2012,  20:59 Найти цитируемый пост)
Какая разрядность? 32? Там нет регистров в 64 бита, так что юзать сдвиги он не сможет. А на x64 сдвиги быстрее доступа к памяти.

причем тут разрядность? Ну не сможет компилятор сдвинуть одной операцией - сдвинет несколькими (псевдокод): r0 = r2 << n; r1 = r2 >> (32 - n);

Автор: Randajad 30.8.2012, 14:20
Какой operator<< для инта? В асмокоде получится shl.
На x86 32bit сдвиг на >= 32 невозможен в принципе. 

Автор: math64 30.8.2012, 14:41
А чего спорить? Проверьте на примере:
Код

long long q;
long m = 1, n = 2;
int main() {
q = ((long long)m << 32) + n;
}

Код

    .comm    q,8,8
.globl m
    .data
    .align 4
    .type    m, @object
    .size    m, 4
m:
    .long    1
.globl n
    .align 4
    .type    n, @object
    .size    n, 4
n:
    .long    2
    .text
.globl main
    .type    main, @function
main:
    pushl    %ebp
    movl    %esp, %ebp
    pushl    %ebx
    movl    m, %eax
    movl    %eax, %edx
    sarl    $31, %edx
    movl    %eax, %ecx
    movl    %edx, %ebx
    movl    %ecx, %ebx
    movl    $0, %ecx
    movl    n, %eax
    movl    %eax, %edx
    sarl    $31, %edx
    addl    %ecx, %eax
    adcl    %ebx, %edx
    movl    %eax, q
    movl    %edx, q+4
    popl    %ebx
    popl    %ebp
    ret
    .size    main, .-main

Сдвиги на 31 бит используются для расширения знака.
Нужно было объявить unsigned. Тогда сдвигов не будет,  хотя будет ненужное сложение:
Код

unsigned long long q;
unsigned long m = 1, n = 2;
int main() {
q = ((unsigned long long)m << 32) + n;
}

Код

    .comm    q,8,8
.globl m
    .data
    .align 4
    .type    m, @object
    .size    m, 4
m:
    .long    1
.globl n
    .align 4
    .type    n, @object
    .size    n, 4
n:
    .long    2
    .text
.globl main
    .type    main, @function
main:
    pushl    %ebp
    movl    %esp, %ebp
    pushl    %ebx
    movl    m, %eax
    movl    $0, %edx
    movl    %eax, %ecx
    movl    %edx, %ebx
    movl    %ecx, %ebx
    movl    $0, %ecx
    movl    n, %eax
    movl    $0, %edx
    addl    %ecx, %eax
    adcl    %ebx, %edx
    movl    %eax, q
    movl    %edx, q+4
    popl    %ebx
    popl    %ebp
    ret
    .size    main, .-main

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)