2015-08-12 8 views
2

Предположим, мы имеем ниже код:Не могу я придумать класс размером 8 байт для uint64_t?

class A { 
     uint32_t X; 
     uint32_t Y; 
}; 

int main() 
{ 
    A a; 
    uint64_t num = (uint64_t)a; 
} 

Компилятор дает ошибку: «Не удается преобразовать из пункта А в uint64_t Нет определения оператора преобразования Пользователь не определен.»

Ожидаемая ошибка и если да, то почему?

+0

Считаете ли вы использование «союза»? – Borgleader

+0

C/C++ имеет 'union' для этого – Slava

+0

В случае, я не хочу объединяться? каковы альтернативы? –

ответ

-2

Определенно неопределенное поведение, но попробуйте

uint64_t num = *reinterpret_cast<uint64_t *>(&a); 
+0

UB при условии, что 'sizeof (a) <= sizeof (uint64_t)'? –

+0

@ Tomasz UB - это UB, независимо. Это не означает, что ваш конкретный компилятор/цель не будет делать то, что вы хотите. См. Http://stackoverflow.com/questions/2397984/undefined-unspecified-and-implementation-defined-behavior – franji1

+0

Вы правы, мои плохие; Я просто пытаюсь выяснить, какая часть этой линии UB искусно –

3

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

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

class A 
{ 
    uint32_t X; 
    uint32_t Y; 
    uint64_t to64() 
    { 
     // convert X and Y to unsigned 64-bit ints 
     uint64_t x64 = X; 
     uint64_t y64 = Y; 
     // left-shift the 64-bit X 32 bits 
     x64 <<= 32; 

     // return the sum 
     return(x64 + y64); 
    } 
}; 

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

0

Вы не указали «континентность» вашего представления. Если вы хотите x быть высоким словом и y младшего слова, вы могли бы добавить оператор приведения к классу:

explicit operator uint64_t() const noexcept 
{ 
    return ((static_cast<uint64_t>(X) << 32) | Y); 
} 

'(uint64_t) obj' или (в идеале) 'static_cast<uint64_t>(obj)' будет вызывать этот метод. explicit препятствует тому, чтобы он назывался неявно - это, вероятно, самая тупая вещь, которую я сказал весь день, но она предотвращает surprises. Дополнительные баллы, если вы используете <cstdint> и std::uint64_t.