Есть ли лучшие способы смягчить это предупреждение? - PullRequest
3 голосов
/ 03 апреля 2019

У меня есть структура, где я использую битовые поля для оптимизации памяти.У меня есть тип uint64_t, и я хочу напечатать его значение.При компиляции он показывает мне это предупреждение: format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 5 has type ‘long unsigned int:48’ [-Wformat=]

Я уже пытался подавить это предупреждение, набрав при компиляции -Wno-format.Мне интересно, есть ли лучший способ сделать это.

Вот код:

#include <stdint.h>
#include <stdio.h>

typedef struct gn_addr 
{
    unsigned int m:1;
    unsigned int st:5;
    unsigned int reserved:10;
    uint64_t mid:48;
} gn_addr ;

void gn_addr__print(gn_addr *self)                                                                                                                                                                         
{                                                                                                                                                                                                          
    printf("M=>%d\nST=>%d\nReserved=>%d\nMID=>%lu\nTotal size %ld bytes\n",                                                                                                                                
         self->m, self->st, self->reserved, self->mid, sizeof(self));                                                                                                                                   
} 

Ответы [ 3 ]

2 голосов
/ 03 апреля 2019

Хотя вы обязательно должны применить исправления в других ответах, чтобы получить переносимые спецификаторы формата, предупреждение будет сохраняться. Причина в том, что дополнительные аргументы для функции с переменным числом, например printf, подвергаются продвижению аргументов. Поощрение аргумента включает целочисленное продвижение.

Правила для целочисленных повышений преобразуют любое целое число с рангом преобразования меньше int / unsigned, а также битовые поля, в int / unsigned. Таким образом, для ваших начальных битовых полей вы автоматически получаете int.

Для целых чисел с более высоким рангом конверсии, чем int / unsigned, повышение не происходит. Таким образом, ваше битовое поле не переведено в uint64_t, и вы получите предупреждение о несоответствии аргументов. Вам нужен актерский состав.

(uint64_t)self->mid

Кстати, поскольку никто не упомянул, спецификатор переносимого формата для size_t (тип оператора sizeof) равен %zu. Вы должны использовать это вместо %ld.

2 голосов
/ 03 апреля 2019

Во-первых, используйте правильный спецификатор формата для типов uint64_t и size_t, используйте макрос PRIu64, как определено в inttypes.h и %zu.

Тем не менее, для переменных битовых полей,

  • вы можете использовать приведение типа (uint64_t)self->mid
  • или вы можете использовать промежуточную переменную типа uint64_t, присвоить значение переменной-члена новой промежуточной переменной и передать его в printf() в качестве соответствующего аргумента для спецификатора формата, например

    uint64_t temp = self->mid;
    printf("%"PRIu64 "\n", temp);
    
0 голосов
/ 03 апреля 2019

Функции типа printf проверяются компиляторами (не все).Компилятор проверяет, совпадает ли спецификатор формата с типом передаваемого аргумента.Вам нужно сделать явное преобразование, чтобы Warning исчезло.Как уже упоминалось в других ответах, существуют некоторые неявные правила целочисленного продвижения, и вам необходимо их знать (благодаря @storyTeller).

Правила целочисленных повышений преобразуют любое целое число с рейтингом конверсии.меньше, чем int / unsigned, а также битовые поля в int / unsigned.Таким образом, для ваших начальных битовых полей вы получаете unsigned int автоматически.

Для целых чисел с более высоким рангом преобразования, чем int / unsigned, повышение не происходит.Таким образом, ваше битовое поле не преобразуется в uint64_t, и вы получаете предупреждение о несоответствии аргументов.Вам нужен приведение.

Попробуйте:

(uint64_t)self->mid

Я уже пытался подавить это предупреждение, набрав при компиляции -Wno-format.Мне интересно, есть ли лучший способ сделать это.

Не стоит подавлять ваши предупреждения.Они созданы по причине.Я бы порекомендовал использовать предупреждающие флаги, такие как -Wall, -Wshadow, -Wextra и другие важные флаги.Они могут помочь вам с развертыванием кода с меньшим количеством ошибок.

Относительно вашего предположения:

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

Я хотел бы отметить, что ваша структура с битовыми полями не будет настолько оптимизирована для памяти, как вы могли бы подумать.Существует нечто, называемое Padding и Data Alignment, которое может помочь вам в дальнейшем уменьшении объема используемой памяти.

Проверьте этот вопрос .

...