Некоторое предположение: если бы я хотел использовать, например, scanf()
для преобразования строки в стандартный целочисленный тип, например uint16_t
, я бы использовал SCNu16
из , например:
#include #include uint16_t x; char *xs = "17"; sscanf(xs, "%" SCNu16, &x);
Но более необычный целочисленный тип, такой как pid_t
, не имеет такой вещи; поддерживается только нормальный целочисленный тип. Чтобы преобразовать другой способ, чтобы portably
printf()
pid_t
, я могу intmax_t
его к intmax_t
и использовать PRIdMAX
, например:
#include #include #include pid_t x = 17; printf("%" PRIdMAX, (intmax_t)x);
Однако, похоже, нет способа переносить scanf()
в pid_t
. Итак, это мой вопрос: как сделать это переносимо?
#include #include pid_t x; char *xs = 17; sscanf(xs, "%u", &x); /* Not portable! pid_t might not be int! /*
Я думал о scanf()
в intmax_t
а затем проверял, что это значение находится в пределах pid_t
до литья в pid_t
, но, похоже, не существует способа получить максимальные или минимальные значения для pid_t
.
Существует одно надежное и портативное решение, которое предназначено для использования strtoimax()
и проверки переполнения.
То есть, я разбираю intmax_t
, проверяю на ошибку из strtoimax()
, а затем также вижу, подходит ли она «вписывается» в pid_t
, отбрасывая ее и сравнивая ее с исходным значением intmax_t
.
#include #include #include #include char *xs = "17"; /* The string to convert */ intmax_t xmax; char *tmp; pid_t x; /* Target variable */ errno = 0; xmax = strtoimax(xs, &tmp, 10); if(errno != 0 or tmp == xs or *tmp != '\0' or xmax != (pid_t)xmax){ fprintf(stderr, "Bad PID!\n"); } else { x = (pid_t)xmax; ... }
Невозможно использовать scanf()
, потому что (как я уже сказал в комментарии) scanf()
не будет обнаруживать переполнения . Но я ошибался, говоря, что ни одна из связанных с strtoll()
функций не принимает intmax_t
; strtoimax()
делает!
Он также не будет работать, чтобы использовать что-либо еще, кроме strtoimax()
если вы не знаете размер вашего целочисленного типа ( pid_t
, в данном случае).
Это зависит от того, насколько портативным вы хотите быть. POSIX говорит, что pid_t
– это целочисленный тип со pid_t
используемый для хранения идентификаторов процессов и идентификаторов групп процессов. На практике вы можете с уверенностью предположить, что это достаточно долго. В противном случае ваш intmax_t
должен быть достаточно большим (так что он примет любой действительный pid_t
); проблема в том, что этот тип может принимать значения, которые не являются законными в pid_t
. Вы застряли между скалой и твердым местом.
Я бы использовал long
и не очень беспокоился об этом, за исключением того, что где-то неясный комментарий, который найдет и наблюдает программный археолог из 100 лет, следовательно, объясняет, почему 256-битный процессор застопорился, когда передал 512-битное значение как pid_t
.
POSIX 1003.1-2008 теперь доступен в Интернете (все его 3872 страницы в формате PDF и HTML). Вы должны зарегистрироваться (бесплатно). Я добрался до него из книжного магазина Open Group .
Все, что я вижу там, это то, что он должен быть знаком целочисленным типом. Ясно, что все действительные intmax_t
целочисленные значения вписываются в intmax_t
. Я не могу найти какую-либо информацию в
или
которая указывает PID_T_MAX или PID_T_MIN или другие такие значения (но я только этим вечером получил доступ к ней, поэтому ее можно было скрыть там, где у меня нет искал его). OTOH, я согласен с моим оригинальным комментарием – я считаю, что 32-битные значения прагматически адекватны, и я бы использовал long
, что было бы 64-битным на 8-битных машинах. Полагаю, что самое худшее, что может случиться, – это то, что процесс с надлежащим преимуществом читает слишком большое значение и отправляет сигнал в неправильный процесс из-за несоответствия типов. Я не уверен, что я буду беспокоиться об этом.
… oooh! … p400 в разделе
Реализация должна поддерживать одну или несколько программных сред, в которых ширины blksize_t, pid_t, size_t, ssize_t и suseconds_t не больше ширины типа long.
Если вы действительно обеспокоены, вы можете _assert(sizeof(pid_t) <= long)
или любой другой тип, который вы выбираете для своего «%».
Как поясняется в этом ответе , спецификация говорит о signed int
. Если «int» изменяется, ваше «% u» по определению меняется вместе с ним.