2009-01-13 28 views
10

Algunos antecedentes: Si quería utilizar para, por ejemplo, scanf() para convertir una cadena en un tipo entero estándar, como uint16_t, que haría uso de SCNu16<inttypes.h>, así:¿Cómo convertir una cadena en un tipo entero poco común?

#include <stdio.h> 
#include <inttypes.h> 
uint16_t x; 
char *xs = "17"; 
sscanf(xs, "%" SCNu16, &x); 

Sin embargo, un mayor tipo entero no común como pid_t no tiene tal cosa; solo los tipos enteros normales son compatibles con <inttypes.h>. Para convertir a la inversa, a printf() portable un pid_t, puedo echarlo a intmax_t y utilizar PRIdMAX, así:

#include <stdio.h> 
#include <inttypes.h> 
#include <sys/types.h> 
pid_t x = 17; 
printf("%" PRIdMAX, (intmax_t)x); 

Sin embargo, no parece ser una manera de forma portátil scanf() en un pid_t. Entonces esta es mi pregunta: ¿cómo hacer esto de forma portátil?

#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! /* 

pensé en scanf() ing a un intmax_t y después de comprobar que el valor está dentro de los límites pid_t 's antes de echar a pid_t, pero no parece ser una manera de conseguir los valores mínimo y máximo o para pid_t .

Respuesta

8

Hay una solución robusta y portátil, que es usar strtoimax() y comprobar si hay desbordamientos.

Es decir, que analizar un intmax_t, compruebe si hay un error de strtoimax(), y luego también ver si "encaja" en un pid_t por colada y compararlo con el valor original 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; 
    ... 
} 

No es posible utilizar scanf(), ya que, (como dije en un comentario) scanf() no detectará desbordamientos. Pero me equivoqué al decir que ninguna de las funciones relacionadas con strtoll() toma un intmax_t; strtoimax() hace!

Tampoco funcionará para usar nada más que strtoimax() a menos que conozca el tamaño de su tipo entero (pid_t, en este caso).

3

Depende exactamente de lo portátil que desee ser. POSIX dice que pid_t es un tipo de entero con signo utilizado para almacenar ID de proceso e ID de grupo de proceso. En la práctica, se puede asumir con seguridad que long es lo suficientemente grande. De lo contrario, su intmax_t debe ser lo suficientemente grande (por lo que aceptará cualquier pid_t válido); el problema es que ese tipo podría aceptar valores que no son legítimos en pid_t. Estás atrapado entre una roca y un lugar duro.

Yo usaría long y no me preocuparía mucho excepto por un oscuro comentario en algún lugar que un arqueólogo de software de 100 años encontrará y observa, da una razón por la cual la CPU de 256 bits se detiene cuando se le entrega una Valor de 512 bits como pid_t.

POSIX 1003.1-2008 ya está disponible en la web (las 3872 páginas en PDF y HTML). Debes registrarte (gratis) Llegué desde el Open Group Bookstore.

Todo lo que veo allí es que debe ser un tipo entero con signo. Claramente, todos los valores enteros con signo válidos caben en intmax_t. No puedo encontrar ninguna información en <inttypes.h> o <unistd.h> que indique PID_T_MAX o PID_T_MIN u otros valores similares (pero esta noche solo he tenido acceso a ella, por lo que podría estar oculta donde no la he buscado). OTOH, estoy de acuerdo con mi comentario original: creo que los valores de 32 bits son pragmáticamente adecuados, y usaría long de todos modos, que sería de 64 bits en máquinas de 8 bits. Supongo que aproximadamente lo peor que podría pasar es que un proceso "apropiadamente privilegiado" lea un valor que sea demasiado grande y envíe una señal al proceso incorrecto debido a una falta de coincidencia de tipos. No estoy convencido de que estaría preocupado por eso.

... oooh! ... p400 bajo <sys/types.h>

La aplicación deberán soportar uno o más entornos de programación en el que los anchos de blksize_t, pid_t, size_t, ssize_t y suseconds_t no son mayores que el ancho de tipo largo.

+1

Escuché que el próximo estándar POSIX solo requeriría que encajara en una intmax_t, por lo que el uso de long out está fuera. Lo que realmente hice fue depender de los documentos de la librería C de GNU diciendo que pid_t siempre sería int, y comentándolo. El código usa otras cosas específicas de glibc de todos modos, por lo que este no es un problema real. – Teddy

+0

Ya obtuve una solución "pragmática adecuada", utilizando una suposición no portátil (en un código que nunca fue portátil en primer lugar). Lo que QUISE era una solución realmente portátil, si tal cosa realmente existe. – Teddy

0

Si realmente te preocupa, puedes _assert(sizeof(pid_t) <= long) o el tipo que elijas para tus '%' cosas.

Como se explica en this answer, la especificación dice signed int. Si 'int' cambia, su '% u' por definición cambia con él.

+2

sizeof en realidad no se ocupa de los posibles valores de un tipo, solo los requisitos de almacenamiento en bytes. Por lo tanto, su código en realidad no garantiza lo que cree que hace. Además, la especificación dice "tipo de entero con signo", no "firmado con int". Gran diferencia. – Teddy

Cuestiones relacionadas