Как переносить строку в необычный целочисленный тип?
Немного предыстории: если бы я хотел использовать, например, scanf()
преобразовать строку в стандартный целочисленный тип, например uint16_t
Я бы использовал SCNu16
от <inttypes.h>
, как это:
#include <stdio.h>
#include <inttypes.h>
uint16_t x;
char *xs = "17";
sscanf(xs, "%" SCNu16, &x);
Но более необычный целочисленный тип, такой как pid_t
не имеет ничего подобного; только нормальные целочисленные типы поддерживаются <inttypes.h>
, Чтобы преобразовать другой способ, чтобы переносимо printf()
pid_t
Я могу привести его к intmax_t
и использовать PRIdMAX
, как это:
#include <stdio.h>
#include <inttypes.h>
#include <sys/types.h>
pid_t x = 17;
printf("%" PRIdMAX, (intmax_t)x);
Тем не менее, похоже, что нет способа переносить scanf()
в pid_t
, Так что это мой вопрос: как это сделать переносимо?
#include <stdio.h>
#include <sys/types.h>
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
,
3 ответа
Существует одно надежное и портативное решение, которое заключается в использовании strtoimax()
и проверьте на переполнение.
То есть я разбираю intmax_t
, проверьте на ошибку от strtoimax()
, а затем также посмотреть, если он "вписывается" в pid_t
бросая его и сравнивая с оригиналом intmax_t
значение.
#include <inttypes.h>
#include <stdio.h>
#include <iso646.h>
#include <sys/types.h>
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
является целочисленным типом со знаком, используемым для хранения идентификаторов процессов и идентификаторов групп процессов. На практике вы можете с уверенностью предположить, что long
достаточно большой. В противном случае ваш intmax_t
должен быть достаточно большим (поэтому он будет принимать любые действительные pid_t
); проблема в том, что тип может принимать значения, которые не являются законными в pid_t
, Вы застряли между камнем и наковальней.
я хотел бы использовать long
и не очень беспокоиться об этом, за исключением неясного комментария где-то, который 100-летний археолог найдет и наблюдает, и объясняет причину, по которой 256-битный ЦП останавливается, когда передает 512-битное значение как pid_t
,
POSIX 1003.1-2008 теперь доступен в Интернете (все 3872 страницы в формате PDF и HTML). Вы должны зарегистрироваться (бесплатно). Я попал в книжный магазин Open Group.
Я вижу только то, что это должен быть целочисленный тип со знаком. Очевидно, что все действительные целые значения со знаком соответствуют intmax_t
, Я не могу найти какую-либо информацию в <inttypes.h>
или же <unistd.h>
это указывает на PID_T_MAX или PID_T_MIN или другие подобные значения (но я только этим вечером получил доступ к нему, поэтому он может быть скрыт там, где я его не искал). OTOH, я поддерживаю свой оригинальный комментарий - я считаю, что 32-битные значения прагматически адекватны, и я бы использовал long
во всяком случае, что будет 64-битным на 8-битных машинах. Я полагаю, что наихудшее, что может случиться, это то, что процесс с соответствующими правами считывает слишком большое значение и посылает сигнал неправильному процессу из-за несоответствия типов. Я не уверен, что буду беспокоиться об этом.
... оооо!... р400 под <sys/types.h>
Реализация должна поддерживать одну или несколько сред программирования, в которых ширина blksize_t, pid_t, size_t, ssize_t и suseconds_t не превышает ширину типа long.
Если вы действительно обеспокоены, вы можете _assert(sizeof(pid_t) <= long)
или любой другой тип, который вы выберете для своего "%".
Как объясняется в этом ответе, в спецификации говорится signed int
, Если "int" меняется, ваш "%u" по определению меняется вместе с ним.