técnicas - tipos de muestreo
pid_t(y tipos similares): ¿por qué, solo por qué? (6)
Cada proceso en el programa tiene un ID de proceso específico. Al llamar a pid, sabemos la ID asignada del proceso actual. Conocer el pid es excepcionalmente importante cuando usamos fork()
, porque devuelve 0
y !=0
para las copias de niños y padres de forma receptiva. Estos dos videos tienen explicaciones claras: video#1 Video#2
Un ejemplo: Supongamos que tenemos el siguiente programa c:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main (int argc, char *argv[])
{
printf("I am %d/n", (int) getpid());
pid_t pid = fork();
printf("fork returned: %d/n", (int) pid);
if(pid<0){
perror("fork failed");
}
if (pid==0){
printf("This is a child with pid %d/n",(int) getpid());
}else if(pid >0){
printf("This is a parent with pid %d/n",(int)getpid());
}
return 0;
}
Si lo ejecuta, obtendrá 0
para el hijo y no zero/greater than zero
para el padre.
¿Cuál es la lógica de las llamadas detrás de getpid()
devuelve un valor de tipo pid_t
lugar de un unsigned int
? O int
? ¿Cómo ayuda esto?
Supongo que esto tiene que ver con la portabilidad? ¿Garantizar que pid_t
es del mismo tamaño en diferentes plataformas que pueden tener diferentes tamaños de int
, etc.?
Creo que es lo contrario: hacer que el programa sea portátil en todas las plataformas, independientemente de si, por ejemplo, un PID es de 16 o 32 bits (o incluso más).
El motivo es permitir que las implementaciones históricas desagradables sigan siendo conformes. Supongamos que su implementación histórica tuvo (bastante común):
short getpid(void);
Por supuesto, los sistemas modernos quieren que los pids sean de al menos 32 bits, pero si el estándar exige:
int getpid(void);
entonces todas las implementaciones históricas que se hubieran usado en short
se volverían no conformes Esto se consideró inaceptable, por pid_t
se creó pid_t
y se permitió a la implementación definir pid_t
la forma que prefiera.
Tenga en cuenta que de ninguna manera está obligado a usar pid_t
en su propio código, siempre y cuando use un tipo que sea lo suficientemente grande como para almacenar cualquier pid ( intmax_t
por ejemplo, funcionaría bien). La única razón por la que pid_t
necesita existir es que el estándar defina getpid
, waitpid
, etc. en términos de ello.
El propósito de este es hacer que pid_t
, o cualquier otro tipo del tipo, sea independiente de la plataforma, de modo que funcione correctamente independientemente de cómo se implemente realmente. Esta práctica se utiliza para cualquier tipo que necesite ser independiente de la plataforma, como:
-
pid_t
: debe ser lo suficientemente grande como para almacenar un PID en el sistema que está codificando.int
tengo entendido, seint
aint
, aunque no estoy familiarizado con la biblioteca C de GNU. -
size_t
: una variableunsigned
capaz de almacenar el resultado del operadorsizeof
. Generalmente igual en tamaño al tamaño de palabra del sistema que está codificando. -
int16_t
(intX_t
): tiene que ser exactamente de 16 bits, independientemente de la plataforma, y no se definirá en plataformas que no utilicen bytes de 2 n bits (normalmente 8 o 16 bits) o, mucho menos frecuentemente, proporcionan un medio para acceder exactamente a 16 bits de un tipo más grande (por ejemplo, los "bytes" del PDP-10, que podrían ser cualquier número de bits contiguos de una palabra de 36 bits, y por lo tanto podrían ser exactamente de 16 bits), y por lo tanto no admite tipos enteros de complemento a dos de 16 bits (como un sistema de 36 bits). En general, se asigna unshort
a computadoras modernas, aunque puede ser unint
en las más antiguas. -
int_least32_t
(int_leastX_t
): tiene que ser el tamaño más pequeño posible que pueda almacenar al menos 32 bits, como 36 bits en un sistema de 36 bits o 72 bits. Generalmente se asigna aint
en computadoras modernas, aunque puede ser unalong
en computadoras antiguas. -
int_fastX_t
: debe ser el tipo más rápido posible que pueda almacenar al menos X bits. Generalmente, es el tamaño de palabra del sistema si(X <= word_size)
(oa veceschar
paraint_fast8_t
), o actúa comoint_leastX_t
if(X > word_size)
) -
intmax_t
: debe ser el ancho máximo de enteros admitido por el sistema. En general, será de al menos 64 bits en los sistemas modernos, aunque algunos sistemas pueden admitir tipos extendidos máslong long
(y si es así, se requiere queintmax_t
sea el más grande de esos tipos). - Y más...
Mecánicamente, permite al instalador del compilador teclear el tipo apropiado al identificador (ya sea un tipo estándar o un tipo interno de nombre extraño) detrás de escena, ya sea creando archivos de encabezado apropiados, codificándolos en el ejecutable del compilador o mediante algún otro método. . Por ejemplo, en un sistema de 32 bits, Microsoft Visual Studio implementará intX_t
y tipos similares de la siguiente manera (nota: comentarios agregados por mí):
// Signed ints of exactly X bits.
typedef signed char int8_t;
typedef short int16_t;
typedef int int32_t;
// Unsigned ints of exactly X bits.
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
// Signed ints of at least X bits.
typedef signed char int_least8_t;
typedef short int_least16_t;
typedef int int_least32_t;
// Unsigned ints of at least X bits.
typedef unsigned char uint_least8_t;
typedef unsigned short uint_least16_t;
typedef unsigned int uint_least32_t;
// Speed-optimised signed ints of at least X bits.
// Note that int_fast16_t and int_fast32_t are both 32 bits, as a 32-bit processor will generally operate on a full word faster than a half-word.
typedef char int_fast8_t;
typedef int int_fast16_t;
typedef int int_fast32_t;
// Speed-optimised unsigned ints of at least X bits.
typedef unsigned char uint_fast8_t;
typedef unsigned int uint_fast16_t;
typedef unsigned int uint_fast32_t;
typedef _Longlong int64_t;
typedef _ULonglong uint64_t;
typedef _Longlong int_least64_t;
typedef _ULonglong uint_least64_t;
typedef _Longlong int_fast64_t;
typedef _ULonglong uint_fast64_t;
Sin embargo, en un sistema de 64 bits, es posible que no se implementen necesariamente de la misma manera, y puedo garantizar que no se implementarán de la misma manera en un sistema arcaico de 16 bits, suponiendo que pueda encontrar una versión de MSVS compatible con uno.
En general, permite que el código funcione correctamente independientemente de los pid_t
específicos de su implementación y que cumpla con los mismos requisitos en cualquier sistema compatible con estándares (por ejemplo, se puede garantizar que pid_t
sea lo suficientemente grande como para mantener cualquier PID válido en el sistema en cuestión, no importa el sistema que estás codificando). También le impide tener que conocer el meollo de la cuestión y tener que buscar nombres internos con los que no esté familiarizado. En resumen, se asegura de que su código funcione igual sin importar si pid_t
(o cualquier otro typedef similar) se implementa como un int
, un short
, un long
, un long long
, o incluso un __Did_you_really_just_dare_me_to_eat_my_left_shoe__
, para que no tenga que hacerlo. .
Además, sirve como una forma de documentación, que le permite saber de qué se trata una variable dada de un vistazo. Considera lo siguiente:
int a, b;
....
if (a > b) {
// Nothing wrong here, right? They''re both ints.
}
Ahora, vamos a intentarlo de nuevo:
size_t a;
pid_t b;
...
if (a > b) {
// Why are we comparing sizes to PIDs? We probably messed up somewhere.
}
Si se usa como tal, puede ayudarlo a localizar segmentos de código potencialmente problemáticos antes de que se rompa algo, y puede hacer que la solución de problemas sea mucho más fácil de lo que sería.
En diferentes plataformas y sistemas operativos, los diferentes tipos (pid_t por ejemplo) pueden ser de 32 bits (sin signo int) en una máquina de 32 bits o de 64 bits (sin signo largo) en una máquina de 64 bits. O, por alguna otra razón, un sistema operativo puede elegir tener un tamaño diferente. Además, al leer el código, queda claro que esta variable representa un "objeto", en lugar de solo un número arbitrario.
Una cosa a destacar, en la mayoría de las respuestas, vi algo como "el uso de pid_t hace que el código funcione en diferentes sistemas" , lo cual no es necesariamente cierto.
Creo que la redacción precisa debería ser: hace que el código se "compile" en diferentes sistemas .
Como, por ejemplo, compilar el código en un sistema que usa pid_t de 32 bits producirá un binario que probablemente se romperá si se ejecuta en otro sistema que usa pid_t de 64 bits.