2015-02-11 1 views
1

Учитывая постоянную структуру в одном API, который должен быть истолкован как 16 последовательных байты uint8_t в других API, есть способ, в C, чтобы сделать это преобразование во время компиляции:Преобразования между константными типами структуры во время компиляции

Что я хотел бы достичь, это что-то вроде

const union { 
    struct a { 
     uint32_t a; 
     uint16_t b; 
     uint16_t c; 
     uint8_t d[8]; 
    } a; 
    uint8_t b[16]; 
} foo = { .a = { 0x12341243, 0x9898, 0x4554, 
       { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 } } }; 

struct from_other_api manifest = { 
    .appuuid = foo.b; 
    // { foo.b[0], foo.b[1], ... } 
}; 

Такой подход, а также второй вариант в комментировал линии, к сожалению, дают как ошибка ошибка: инициализатор элемент не является постоянной, хотя это, безусловно, выглядит как постоянная ,

Деловая причина заключается в том, что оба определения struct from_other_api manifest и постоянная память blob имеют API, который нельзя изменять. Преобразование может быть сделано вручную, как

struct from_other_api manifest = { 
    .appuuid = { 0x43, 0x12, 0x34, 0x12, 0x98, 0x98, 0x54, 0x45, 
       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 } 
}; 

, но следует избегать, так как это шаблон регулярного орать быть автоматизирован.

+0

Вы используете 'C99' или выше? –

+0

Я использую gcc без указания '-std = c99'; даже если это может выглядеть так, это может быть расширение gnu ... –

ответ

1

В C постоянных переменных не могут быть использованы в постоянных выражений.

Если вы можете инициализировать manifest во время выполнения, вы можете сделать это с помощью memcpy, как в ответе Snaipes.

Но если во время компиляции необходимо инициализировать manifest, вам может потребоваться (ab) использовать препроцессор. Это будет не слишком красиво, но оно работает:

#define ID 0x12341243, 0x9898, 0x4554, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 

#define FOO(nnn) { .a = FOO2(nnn) } 
#define FOO2(a, b, c, d, e, f, g, h, i, j, k) \ 
    { a, b, c, { d, e, f, g, h, i, j, k } } 

#define MAN(nnn) MAN2(nnn) 
#define MAN2(a, b, c, d, e, f, g, h, i, j, k) \ 
    { a >> 0 & 0xFF, a >> 8 & 0xFF, a >> 16 & 0xFF, a >> 24 & 0xFF, \ 
    b >> 0 & 0xFF, b >> 8 & 0xFF, \ 
    c >> 0 & 0xFF, c >> 8 & 0xFF, \ 
    d, e, f, g, h, i, j, k } 

const union { 
    ... 
} foo = FOO(ID); 

struct from_other_api manifest = { 
    .appuuid = MAN(ID) 
}; 
+0

Это довольно. Учитывая, что первое предложение является истинным, а постоянные переменные не могут использоваться в постоянном выражении, тогда это время магии магии. –

1

Вы не можете передавать ничего, кроме литералов, в инициализаторы массива. Использование memcpy(3) вместо:

struct from_other_api manifest = { 
    // initialize other members 
}; 
memcpy(manifest.appuuid, foo.b, sizeof (manifest.appuuid)); 
2

Эта декларация не объявить переменную.

struct a { 
    uint32_t a; 
    uint16_t b; 
    uint16_t c; 
    uint8_t d[8]; 
}; 

Чтобы объявить переменную с именем a с той же структурой внутри union, используйте:

const union { 
    struct { 
     uint32_t a; 
     uint16_t b; 
     uint16_t c; 
     uint8_t d[8]; 
    } a; // now a is accessible with a.a, a.b, a.c and a.d[i]. 
    uint8_t b[16]; 
} foo = { .a = { 0x12341243, 0x9898, 0x4554, 
      { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 } } }; 
+0

Правда, я отредактирую вопрос, так как он содержит ошибку копирования-вставки. –

 Смежные вопросы

  • Нет связанных вопросов^_^