Re Legacy code: format '% d ожидает аргумент типа int, но аргумент 3 имеет тип long long unsigned int [-Wformat]

Я часто пытаюсь создать много старых симуляторов и инструментов для архивирования дисков и лент с недавним GCC. Некоторые ошибки легко исправить, но я не так хорош программист.

Я получаю:

itstar.c: В функции 'addfiles:
itstar.c: 194: 4: warning: format '% d ожидает аргумент типа' int, но аргумент 2 имеет тип 'long unsigned int [-Wformat]
itstar.c: 194: 4: warning: format '% d ожидает аргумент типа' int, но аргумент 3 имеет тип 'long unsigned int [-Wformat]

из этого фрагмента кода:

/* add files to a DUMP tape */
/* output buffer must have been initialized with resetbuf() */
static void addfiles(int argc,char **argv)
{
    int c=argc;
    char **v=argv;

    while(c--) {
        addfile(argc,argv,*v++);
    }
    if(verify)
        printf("Approximately %d.%d' of tape used\n",count/bpi/12,
            (count*10/bpi/12)%10);
}

Где строка 194 является третьей от последней, начиная с printf.

Файл isstar.c, из tapetools, код здесь.

Он строит, несмотря на предупреждение, но я предпочитаю знать, как его предотвратить,
поэтому результат более эффективен и вероятность повреждения данных меньше.

Пожалуйста, что я пропустил, и мне нужно изменить?

Спасибо заранее.

+3
источник поделиться
3 ответа

Используйте спецификатор формата %lu вместо %d, и ваш компилятор должен перестать жаловаться.

printf("Approximately %lu.%lu' of tape used\n", count/bpi/12, (count*10/bpi/12)%10);
+5
источник

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

Глядя на источник, мы можем видеть, что как count, так и bpi длинны unsigned:

extern unsigned long bpi; /* tape density in bits per inch */
extern unsigned long count; /* count of tape frames written */ 

для них был бы правильный тип спецификатора формата %lu.

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

"Approximately %d.%d' of tape used\n"
               ^^ ^^
               1  2

оба спецификатора преобразования 1 и 2 равны %d, что означает, что printf ожидает, что следующие два аргумента будут иметь тип int, но они действительно имеют тип unsigned long.

Если мы посмотрим черновик стандарта C99 раздел 7.19.6.1 Функция fprintf, которая также охватывает printf для спецификаторов формата, говорит:

Если спецификация преобразования недействительна, поведение undefined. 248) Если какой-либо аргумент не является правильным типом для соответствующей спецификации преобразования, поведение undefined.

поэтому вам нужно исправить неверный формат, и ваше предупреждение исчезнет, ​​и вы вернетесь в хорошо определенную область поведения.

+5
источник

Используйте %lu вместо %d. %d используется для типа int, %lu для unsigned long.

+2
источник

Посмотрите другие вопросы по меткам или Задайте вопрос