52 votes

Pourquoi getpid() retourne-t-il pid_t au lieu de int ?

Quelle est la logique derrière des appels comme getpid() renvoyant une valeur de type pid_t au lieu d'un unsigned int ? Ou int ? En quoi cela peut-il aider ?

Je suppose que cela a à voir avec la portabilité ? Garantir que pid_t est de la même taille sur différentes plates-formes qui peuvent avoir des tailles différentes d'éléments d'information. int etc.

45voto

zvrba Points 14028

Je pense que c'est le contraire : rendre le programme portable sur toutes les plateformes, indépendamment du fait que, par exemple, un PID soit de 16 ou 32 bits (ou même plus).

38voto

R.. Points 93718

La raison en est de permettre à de méchantes implémentations historiques d'être encore conformes. Supposons que votre implémentation historique ait (plutôt commun) :

short getpid(void);

Bien sûr, les systèmes modernes veulent que les pids soient au moins de 32 bits, mais si la norme l'exigeait :

int getpid(void);

alors toutes les implémentations historiques qui ont utilisé short deviendrait non-conforme. Cette situation a été jugée inacceptable, de sorte que pid_t a été créé et la mise en œuvre a été autorisée à définir pid_t de la manière qu'il préfère.

Notez que vous n'êtes en aucun cas obligé d'utiliser pid_t dans votre propre code tant que vous utilisez un type suffisamment grand pour stocker tout pid ( intmax_t par exemple, fonctionnerait très bien). La seule raison pid_t doit existe, c'est à la norme de définir getpid , waitpid etc. en fonction de celui-ci.

9voto

Justin Time Points 563

Le but est de faire pid_t ou tout autre type de ce genre, indépendant de la plate-forme, de sorte qu'il fonctionne correctement quelle que soit la manière dont il est mis en œuvre. Cette pratique est utilisée pour tout type qui doit être indépendant de la plate-forme, tel que :

  • pid_t : Doit être assez grand pour stocker un PID sur le système pour lequel vous codez. Correspond à int pour autant que je sache, bien que je ne sois pas le plus familier avec la bibliothèque GNU C.
  • size_t : Un unsigned variable capable de stocker le résultat de la sizeof opérateur. Généralement de taille égale à la taille des mots du système pour lequel vous codez.
  • int16_t ( intX_t ) : Doit être exactement de 16 bits, quelle que soit la plateforme, et ne sera pas défini sur les plateformes qui n'utilisent pas 2 n -(typiquement 8 ou 16 bits) ou, beaucoup plus rarement, fournissent un moyen d'accéder à exactement 16 bits d'un type plus grand (par exemple, les "octets" du PDP-10, qui peuvent être n'importe quel nombre de bits contigus d'un mot de 36 bits, et donc être exactement de 16 bits), et ne supportent donc pas les types entiers de complément à deux de 16 bits (comme un système de 36 bits). Correspond généralement à short sur les ordinateurs modernes, bien que cela puisse être un int sur les plus anciens.
  • int_least32_t ( int_leastX_t ) : Doit être la plus petite taille possible pouvant stocker au moins 32 bits, par exemple 36 bits sur un système à 36 ou 72 bits. Correspond généralement à int sur les ordinateurs modernes, bien que cela puisse être un long sur les plus anciens.
  • int_fastX_t : Doit être le type le plus rapide possible qui peut stocker au moins X bits. En général, c'est la taille du mot du système si (X <= word_size) (ou parfois char para int_fast8_t ), ou agit comme int_leastX_t si (X > word_size) )
  • intmax_t : Doit être la largeur maximale des entiers supportée par le système. Généralement, ce sera au moins 64 bits sur les systèmes modernes, bien que certains systèmes puissent supporter des types étendus plus larges que long long (et si oui, intmax_t doit être le plus grand de ces types).
  • Et plus encore...

Mécaniquement, il permet à l'installateur du compilateur de typedef le type approprié à l'identifiant (qu'il s'agisse d'un type standard ou d'un type interne maladroitement nommé) en coulisse, que ce soit en créant les fichiers d'en-tête appropriés, en le codant dans l'exécutable du compilateur ou par une autre méthode. Par exemple, sur un système 32 bits, Microsoft Visual Studio implémentera la fonction intX_t et des types similaires comme suit (note : commentaires ajoutés par moi) :

// 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;

Sur un système 64 bits, cependant, ils ne seront pas nécessairement implémentés de la même manière, et je peux garantir qu'ils ne seront pas implémentés de la même manière sur un système 16 bits archaïque, en supposant que vous puissiez trouver une version de MSVS compatible avec celui-ci.

Globalement, elle permet au code de fonctionner correctement, quelles que soient les spécificités de votre mise en œuvre, et de répondre aux mêmes exigences sur n'importe quel système compatible avec les normes (par ex. pid_t peut être garanti comme étant suffisamment grand pour contenir tout PID valide sur le système en question, quel que soit le système pour lequel vous codez). Il vous évite également d'avoir à connaître les détails et de devoir chercher les noms internes que vous ne connaissez peut-être pas. En bref, cela permet de s'assurer que votre code fonctionne de la même manière, peu importe si pid_t (ou tout autre typedef similaire) est implémentée comme un int , a short , a long , a long long ou même un __Did_you_really_just_dare_me_to_eat_my_left_shoe__ pour que vous n'ayez pas à le faire.


En outre, il sert de documentation, vous permettant de savoir en un coup d'œil à quoi sert une variable donnée. Prenons l'exemple suivant :

int a, b;

....

if (a > b) {
    // Nothing wrong here, right?  They're both ints.
}

Maintenant, essayons encore une fois :

size_t a;
pid_t b;

...

if (a > b) {
    // Why are we comparing sizes to PIDs?  We probably messed up somewhere.
}

S'il est utilisé comme tel, il peut vous aider à localiser des segments de code potentiellement problématiques avant que quelque chose ne casse, et peut rendre le dépannage beaucoup plus facile qu'il ne le serait autrement.

9voto

Maz Points 2701

Sur des plateformes et des systèmes d'exploitation différents, les différents types (pid_t par exemple) peuvent être de 32 bits (unsigned int) sur une machine 32 bits ou de 64 bits (unsigned long) sur une machine 64 bits. Ou, pour une autre raison, un système d'exploitation peut choisir d'avoir une taille différente. En outre, il est clair à la lecture du code que cette variable représente un "objet", plutôt qu'un simple nombre arbitraire.

2voto

Chaque processus du programme possède un ID de processus spécifique. En appelant pid, nous connaissons l'ID assigné au processus actuel.Connaître le pid est exceptionnellement important lorsque nous utilisons fork() car il renvoie 0 y !=0 Ces deux vidéos fournissent des explications claires : vidéo#1 Vidéo n°2

Un exemple : Supposons que nous ayons le programme c suivant :

#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 vous l'exécutez, vous obtiendrez 0 pour les enfants et les non zero/greater than zero pour le parent.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X