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

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