Как переносить строку в необычный целочисленный тип?
Некоторое предположение: если бы я хотел использовать, например, scanf()
, чтобы преобразовать строку в стандартный целочисленный тип, например uint16_t
, Id использовать SCNu16
из <inttypes.h>
, например:
#include <stdio.h>
#include <inttypes.h>
uint16_t x;
char *xs = "17";
sscanf(xs, "%" SCNu16, &x);
Но более необычный целочисленный тип типа pid_t
не имеет такой вещи; <inttypes.h>
поддерживаются только нормальные целые типы. Чтобы преобразовать другой способ, в переносимый printf()
a 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()
ing к intmax_t
, а затем проверял, что значение находится в пределах pid_t
s до кастинга до pid_t
, но, похоже, не существует способа получить максимум или минимум значения для pid_t
.
Ответы
Ответ 1
Существует одно надежное и портативное решение, которое должно использовать 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
в этом случае).
Ответ 2
Это зависит от того, насколько портативным вы хотите быть. 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 Bookstore.
Все, что я вижу, это то, что это должен быть целочисленный тип со знаком. Ясно, что все допустимые значащие целочисленные значения вписываются в intmax_t
. Я не могу найти какую-либо информацию в <inttypes.h>
или <unistd.h>
, которая указывает PID_T_MAX или PID_T_MIN или другие такие значения (но я только этим вечером получил доступ к ней, чтобы ее можно было скрыть там, где я ее не искал), OTOH, я согласен с моим оригинальным комментарием - я считаю, что 32-битные значения прагматически адекватны, и я бы использовал long
в любом случае, что было бы 64-битным на 8-битных машинах. Полагаю, что самое худшее, что может случиться, - это то, что процесс с надлежащим преимуществом читает слишком большое значение и отправляет сигнал в неправильный процесс из-за несоответствия типов. Я не уверен, что я буду беспокоиться об этом.
... oooh!... p400 под <sys/types.h>
Реализация должна поддерживать одну или несколько программных сред, в которых ширина из blksize_t, pid_t, size_t, ssize_t и suseconds_t не больше ширины типа long.
Ответ 3
Если вы действительно обеспокоены, вы можете _assert(sizeof(pid_t) <= long)
или любой тип, который вы выберете для своего материала%.
Как объясняется в этом ответе, спецификация говорит signed int
. Если "int" изменяется, ваш "% u" по определению изменяется вместе с ним.