2017-01-06 5 views
1

У меня есть:-структуруТот же код для printf, другой выход?

typedef struct cbor { 
    cbor_type type; 

    uint64_t length; //x2 for maps 

    struct cbor* child; 
    struct cbor* next; 
    struct cbor* parent; 

    union { 
    const uint8_t* bytes; 
    long sint; 
    uint64_t uint; 
    double real; 
    } value; 
} cbor; 

Я инициализировать указатель на cbor с таНос, и установить длину 0, а значение UINT и SINT до 1, и введите в CBOR_INTEGER.

У меня есть функция, которая должна печатать информацию о cbor структуры:

void cbor_print_item(cbor* item){ 
    os_printf("c2 = %d %d %d\n", item->value.sint, item->value.uint, item->length); 

    switch(item->type){ 
     case CBOR_INTEGER: 
      os_printf("type:integer\nsval:%d\nuval:%d\nlength:%d\n", item->value.sint, item->value.uint, item->length); 
      os_printf("type:integer\n"); 
      os_printf("sval:%d\n", item->value.sint); 
      os_printf("uval:%d\n", item->value.uint); 
      os_printf("length:%d\n", item->length); 
      break; 
     case CBOR_STRING: 
      os_printf("type:\tstring\n"); 
      os_printf("val:\t%s\n", item->value.bytes); 
      os_printf("length:\t%d\n", item->length); 
      break; 
     case CBOR_REAL: 
      os_printf("type:\treal\n"); 
      os_printf("length:\t%d\n", item->length); 
      os_printf("val:\t%f\n", item->value.real); 
      break; 
     default: 
      os_printf("error!\n"); 
    } 
} 

Однако, я не получить ожидаемый результат. Выход для переключателя printf должен быть одинаковым, не так ли? Мой вывод:

c2 = 1 1 0 
type:integer 
sval:1 
uval:1 
length:0 
type:integer 
sval:1 
uval:144 
length:144 

Я пишу код для espressif, следовательно, «os_printf», насколько я знаю, он работает как «Printf».

Я действительно озадачен и не могу понять, почему это происходит.

EDIT 1: Я знаю, что не должен использовать «% d» для long и uint64. Вопрос в том, почему выходы разные? Я не изменяю значения между печатью, поэтому те же значения должны быть напечатаны.

EDIT 2: Этот вопрос не касается союзов, их инициализации, лучшего способа печати uint64 или долгого.

Возникает вопрос: почему же

os_printf("type:integer\nsval:%d\nuval:%d\nlength:%d\n", item->value.sint, item->value.uint, item->length); 

печати

type:integer 
sval:1 
uval:1 
length:0 

и

os_printf("type:integer\n"); 
    os_printf("sval:%d\n", item->value.sint); 
    os_printf("uval:%d\n", item->value.uint); 
    os_printf("length:%d\n", item->length); 

отпечатки

type:integer 
sval:1 
uval:144 
length:144 
+2

Почему вы используете спецификатор формата '% d' для' long' и 'uint64_t' типов? И почему вы думаете, что члены профсоюза, которые вы явно не задали, будут иметь значимое значение? –

+0

Я установил их явно, length, value.uint и value.sint. и выход должен быть одинаковым в любом случае, не так ли? даже если я не инициализировал их и не использовал неправильный формат. единственное различие заключается в том, что в первом случае я печатаю все с одним printf, а во втором я вызываю три printf's –

+2

. Если вы установите 'sint' * после *, вы установите' uint', тогда 'uint' больше не имеет значимого значения. –

ответ

4

У вас есть неопределенное поведение, потому что вы пытаетесь распечатать uint64_t с использованием формата %d. printf (и другие функции, которые принимают переменное количество аргументов) должны знать тип (и размер) аргументов. Он получает эту информацию из спецификаторов формата. Поскольку вы дали ему %d вместо правильного формата, он пытается прочитать int вместо uint64_t. См. Пример this.

+0

% lld для uint64_t и% ld для долгого решения проблемы, поэтому я принял этот ответ. По-прежнему не понимаю, почему, если я печатаю все в одном printf, это работает по-другому, чем когда я печатаю в нескольких printf, но я думаю, это не имеет большого значения. –

+0

Вы должны использовать макрос 'PRIu64' в качестве указателя формата для' uint64_t' (т. Е. '"% "PRIu64', как показано в моем примере). '% lld' для' long long' (подписанный, а не беззнаковый). – Kevin

0

с sprintf(format, val1, val2) вы кладете val1 и val2 в стек параметра в sprintf, а затем sprintf будет извлекать значения из этого стека в соответствии со строкой формата, которая слепо работает над значениями, не зная фактических размеров. так в quintessenz: неопределенное поведение

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