Пожалуйста, почему этот код печатается с дополнительным n, когда я его запускаю?

Я пытаюсь получить pid, используя этот код. Но когда я запустил скомпилированный код. Я получаю сообщение об ошибке «предупреждение: формат указывает тип« unsigned long », но аргумент имеет тип« pid_t »(также известный как« int »)[-Wformat]».

Когда я изменил спецификатор формата на просто «%lu», он печатается без дополнительного символа.

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
pid_t pid = getpid();

printf("pid: %lun", pid);
}

Я ожидал pid «60316». Я получаю pid «60316n».

И что вы ожидаете от n в %lun? Это должно было быть \n?   —  person jennylearner    schedule 04.10.2019

n не является частью спецификатора формата %lu; это часть обычной строки. Распечатывается как есть.   —  person jennylearner    schedule 04.10.2019

В дополнение к комментарию UnholySheep, %lu специально используется для печати unsigned long, последующее n просто обрабатывается как строковый литерал, точно так же, как префикс pid :.   —  person jennylearner    schedule 04.10.2019

Хорошо. Я понял теперь. Спасибо всем за то, что сделали это яснее.   —  person jennylearner    schedule 04.10.2019

См. также:  Почему допустимо переплетать операторы switch / for / if в C / C ++?
Понравилась статья? Поделиться с друзьями:
IT Шеф
Комментарии: 2
  1. jennylearner

    n печатает по той же причине, что и p печатает. n не является частью спецификатора.

          vvv  --- specifier for unsigned long 
    "pid: %lun"
     ^^^^^   ^ --- non-specifier characters
    

    В стороне:

    Тип данных pid_t – это тип целого числа со знаком, который способен представлять идентификатор процесса

    См. Каков правильный спецификатор printf для печати pid_t?

    Я проверил ссылку. Это было полезно. person jennylearner; 04.10.2019

  2. jennylearner

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

    Из предупреждающего сообщения мы можем сказать, что pid является int. Таким образом, правильный спецификатор формата — %d.

    Спецификатор %lu был бы правильным, если бы pid имел тип unsigned long int.

    Спецификаторы формата — это своего рода миниатюрный язык программирования. Основной спецификатор формата для типа unsigned int%u, и вы можете изменить его для печати unsigned long int вместо модификатора l (буква ell): %lu.

    Но когда вы пишете %lun, n на самом деле не является частью какого-либо спецификатора формата, поэтому оно печатается как само по себе.

    (Кроме того, вам повезло: несмотря на несоответствие между типом pid и спецификатором формата %lu, вы все равно получили разумное значение.)

    Как правило, выровнять аргументы и спецификаторы формата несложно: int для %d, unsigned int для %u или %x, long int для %ld, float или double для %f и т. д. Но какой спецификатор правильно использовать для pid, который имеет тип pid_t? Сегодня на вашем компьютере pid_t выглядит как int, поэтому %d будет правильным, но что, если на каком-то другом компьютере он будет иметь другой тип? Как написать один фрагмент кода, который будет корректно работать на любом компьютере? Один из способов — выбрать тип, который, вероятно, является правильным, и использовать спецификатор для этого типа, а затем использовать явное приведение для преобразования вашего значения в выбранный вами тип. Так:

    printf("pid: %d\n", (int)pid);
    

    Или вот так:

    printf("pid: %lu\n", (unsigned long int)pid);
    

    Если приведение не требуется (если выбранный вами спецификатор формата уже верен для типа pid на вашем компьютере), приведение не помешает.

    Наконец, поздравляю с использованием компилятора, который фактически выдал вам предупреждающее сообщение:

    предупреждение: формат указывает тип «unsigned long», но аргумент имеет тип «pid_t» (он же «int»)

    Слишком много начинающих программистов застряли на старых компиляторах, которые не выводят подобных предупреждений, и это, очевидно, значительно усложняет отслеживание проблем, вызванных несоответствием спецификаторов формата! (Ваш компилятор был особенно полезен тем, что он дал вам как видимый тип pid, а именно pid_t, так и фактический базовый тип int.)

    Так что я просто распечатал n. Теперь я понимаю. Спасибо person jennylearner; 04.10.2019

    Итак, я ошибаюсь, используя unsigned long для pid? Я думал, что это нормально, так как диапазон больше. person jennylearner; 04.10.2019

    Да, это неправильно. Если pid действительно является целым числом, строго говоря, неправильно печатать его как беззнаковое с u (хотя вам почти всегда это сойдет с рук). Печатать с l хуже, потому что pid (во всяком случае, на вашей машине) определенно недолго. Вам часто это тоже сойдет с рук на 32-битной машине, где и int, и long int являются 32-битными. (Но это не сработает на моей машине, где int — 32 бита, а long — 64.) person jennylearner; 04.10.2019

Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: