Как переносить строку в необычный целочисленный тип? - PullRequest
11 голосов
/ 13 января 2009

Немного предыстории: если бы я хотел использовать, например, 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() 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() перед intmax_t, а затем проверял, что значение находится в пределах pid_t, перед приведением к pid_t, но, похоже, нет способа получить максимум или минимальные значения для pid_t.

Ответы [ 3 ]

8 голосов
/ 12 февраля 2009

Существует одно надежное и портативное решение, которое должно использовать 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).

3 голосов
/ 13 января 2009

Это зависит от того, насколько именно вы хотите быть портативным. 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-битных машинах. Я предполагаю, что примерно худшее, что может случиться, это то, что процесс с соответствующими привилегиями считывает слишком большое значение и посылает сигнал неправильному процессу из-за несоответствия типов. Я не уверен, что буду беспокоиться об этом.

... оооо! ... p400 под <sys/types.h>

Реализация должна поддерживать одну или несколько сред программирования, в которых ширина blksize_t, pid_t, size_t, ssize_t и suseconds_t не больше ширины типа long.

0 голосов
/ 13 января 2009

Если вы действительно обеспокоены, вы можете _assert(sizeof(pid_t) <= long) или любой другой тип, который вы выберете для своей вещи '%'.

Как объяснено в этом ответе , спецификация гласит signed int. Если «int» меняется, ваш «% u» по определению меняется вместе с ним.

...