Я пытаюсь получить 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
n
печатает по той же причине, что иp
печатает.n
не является частью спецификатора.В стороне:
Тип данных
pid_t
– это тип целого числа со знаком, который способен представлять идентификатор процессаСм. Каков правильный спецификатор printf для печати pid_t?
Я проверил ссылку. Это было полезно. — person jennylearner; 04.10.2019
Строка формата, которую вы передаете
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
будет правильным, но что, если на каком-то другом компьютере он будет иметь другой тип? Как написать один фрагмент кода, который будет корректно работать на любом компьютере? Один из способов — выбрать тип, который, вероятно, является правильным, и использовать спецификатор для этого типа, а затем использовать явное приведение для преобразования вашего значения в выбранный вами тип. Так:Или вот так:
Если приведение не требуется (если выбранный вами спецификатор формата уже верен для типа
pid
на вашем компьютере), приведение не помешает.Наконец, поздравляю с использованием компилятора, который фактически выдал вам предупреждающее сообщение:
Слишком много начинающих программистов застряли на старых компиляторах, которые не выводят подобных предупреждений, и это, очевидно, значительно усложняет отслеживание проблем, вызванных несоответствием спецификаторов формата! (Ваш компилятор был особенно полезен тем, что он дал вам как видимый тип
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