Como converter portably uma string em um tipo inteiro incomum?
Pergunta
Alguns antecedentes: Se eu quisesse usar para, por exemplo, scanf()
para converter uma string em um tipo inteiro padrão, como uint16_t
, eu usaria SCNu16
de <inttypes.h>
, como este:
#include <stdio.h>
#include <inttypes.h>
uint16_t x;
char *xs = "17";
sscanf(xs, "%" SCNu16, &x);
Mas um tipo inteiro mais incomum como pid_t
não tem qualquer coisa semelhante, apenas os tipos inteiros normais são apoiados por <inttypes.h>
. Para converter o outro lado, para printf()
portably um pid_t
, posso lançá-lo aos intmax_t
e uso PRIdMAX
, como este:
#include <stdio.h>
#include <inttypes.h>
#include <sys/types.h>
pid_t x = 17;
printf("%" PRIdMAX, (intmax_t)x);
No entanto, não parece ser uma maneira de scanf()
portably em um pid_t
. Portanto, esta é a minha pergunta: Como fazer isso portably
#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! /*
pensei em scanf()
ing a um intmax_t
e depois verificar que o valor está dentro dos limites do pid_t
antes de lançar a pid_t
, mas não parece ser uma maneira de obter o valor máximo ou mínimo para pid_t
.
Solução
Há uma solução robusta e portátil, que é usar strtoimax()
e verificar se há excessos.
Isto é, eu analisar um intmax_t
, verifique se há um erro de strtoimax()
, e depois também ver se "encaixa" em um pid_t
por convertê-lo e compará-lo com o valor intmax_t
originais.
#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;
...
}
Não é possível usar scanf()
, porque, (como eu disse em um comentário) scanf()
não irá detectar excessos . Mas eu estava errado em dizer que nenhuma das funções strtoll()
relacionada leva uma intmax_t
; strtoimax()
faz!
Ele também não vai funcionar para o uso de qualquer outra coisa do que strtoimax()
se você não sabe o tamanho de seu tipo inteiro (pid_t
, neste caso).
Outras dicas
Depende exatamente como portátil que você quer ser. POSIX diz que pid_t
é um tipo inteiro assinado usado para IDs processo de armazenamento e IDs de grupo processo. Na prática, você poderia assumir com segurança que long
é grande o suficiente. Na falta deste, o seu intmax_t
deve ser grande o suficiente (para que ele irá aceitar qualquer pid_t
válido); O problema é que esse tipo poderia aceitar valores que não são legítimos em pid_t
. Você está preso entre uma rocha e um lugar duro.
Gostaria de usar long
e não se preocupar muito sobre isso, exceto para um comentário em algum lugar obscuro que um arqueólogo software de 100 anos, portanto, vai encontrar e observar dá uma razão para que a CPU de 256 bits está se deteriorando a um impasse quando entregou um 512 valor bit como um pid_t
.
POSIX 1.003,1-2008 já está disponível na web (todo 3872 páginas do mesmo, em PDF e HTML). Você tem que registrar (gratuito). Eu tenho a ele a partir do Open grupo Livraria .
Tudo o que vejo lá é que ele deve ser um tipo inteiro assinado. Claramente, todos os valores inteiros assinados válidos caber em intmax_t
. Não consigo encontrar qualquer informação em <inttypes.h>
ou <unistd.h>
que indica PID_T_MAX ou PID_T_MIN ou outros valores (mas eu tenho apenas esta noite tem acesso a ele, para que ele pudesse ser escondido onde eu não olhei para ele). OTOH, eu mantenho a minha comentário original - Eu acredito que valores de 32 bits são pragmaticamente adequada, e eu usaria long
qualquer maneira, o que seria de 64 bits em máquinas de 8 bits. Suponho que cerca a pior coisa que poderia acontecer é que um processo de 'apropriadamente privilegiada' ler um valor que era muito grande, e enviou um sinal para o processo errado devido a uma incompatibilidade de tipos. Eu não estou convencido de que eu estaria preocupado com isso.
... oooh! ... P400 sob <sys/types.h>
A implementação deve apoiar um ou mais programação ambientes em que as larguras de blksize_t, pid_t, size_t, ssize_t e suseconds_t não são maiores do que a largura do tipo long.
Se você está realmente em causa pode _assert(sizeof(pid_t) <= long)
ou qualquer que seja o tipo que você escolher para o seu material '%'.
Como explicado na esta resposta , a especificação diz signed int
. Se as mudanças 'int', o '% U' por alterações de definição com ele.