Как переносить строку в необычный целочисленный тип?

Немного предыстории: если бы я хотел использовать, например, 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" по определению меняется вместе с ним.

Другие вопросы по тегам