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

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