it-swarm.it

pid_t (e tipi simili) - perché, solo perché?

Qual è la logica dietro chiamate come getpid() che restituiscono un valore di tipo pid_t invece di un unsigned int? O int? In che modo questo aiuta?

Immagino che questo abbia a che fare con la portabilità? Garantire che pid_t abbia le stesse dimensioni su piattaforme diverse che possono avere dimensioni diverse di ints ecc.?

43
ntl0ve

Penso che sia l'opposto: rendere il programma portatile attraverso piattaforme, indipendentemente dal fatto che, ad esempio, un PID sia 16 o 32 bit (o anche più lungo).

39
zvrba

La ragione è di permettere che implementazioni storiche cattive siano ancora conformi. Supponiamo che la tua implementazione storica abbia (piuttosto comune):

short getpid(void);

Ovviamente i sistemi moderni vogliono che i pids siano almeno a 32 bit, ma se lo standard richiede:

int getpid(void);

allora tutte le implementazioni storiche che avevano usato short diventerebbero non conformi. Questo è stato ritenuto inaccettabile, quindi pid_t è stato creato e l'implementazione è stata autorizzata a definire pid_t in qualsiasi modo preferisca.

Nota che non sei obbligato a usare pid_t nel tuo codice, purché tu usi un tipo abbastanza grande per memorizzare qualsiasi pid (per esempio, intmax_t funzionerebbe bene). L'unica ragione per cui pid_t ha bisogno di exist è che lo standard definisca getpid, waitpid, ecc. In termini di esso.

31
R..

Su piattaforme e sistemi operativi diversi, tipi diversi (pid_t per esempio) potrebbero essere 32 bit (unsigned int) su una macchina a 32 bit o 64 bit (senza segno lungo) su una macchina a 64 bit. Oppure, per qualche altro motivo, un sistema operativo potrebbe scegliere di avere una dimensione diversa. Inoltre, rende chiaro quando legge il codice che questa variabile rappresenta un "oggetto", piuttosto che un numero arbitrario.

9
Maz

Lo scopo è quello di rendere pid_t, o qualsiasi altro tipo di ordinamento, indipendente dalla piattaforma, in modo tale che funzioni correttamente indipendentemente da come è effettivamente implementato. Questa pratica è utilizzata per qualsiasi tipo che deve essere indipendente dalla piattaforma, come ad esempio:

  • pid_t: deve essere abbastanza grande da contenere un PID sul sistema per il quale stai codificando. Mappe per int per quanto ne so, anche se non sono più familiare con la libreria C GNU.
  • size_t: una variabile unsigned in grado di memorizzare il risultato dell'operatore sizeof. Generalmente di dimensioni uguali alle dimensioni di Word del sistema per cui stai codificando.
  • int16_t (intX_t): deve essere esattamente a 16 bit, indipendentemente dalla piattaforma, e non sarà definito su piattaforme che non usano 2n-bit byte (in genere 8 o 16 bit) o, molto meno frequentemente, forniscono un mezzo per accedere esattamente a 16 bit di un tipo più grande (ad esempio, i "byte" del PDP-10, che potrebbero essere un numero qualsiasi di bit contigui fuori da un Word a 36 bit, e quindi potrebbe essere esattamente 16 bit), e quindi non supportano i tipi interi a complemento a due bit di 16 bit (come un sistema a 36 bit). Generalmente esegue il mapping a short su computer moderni, sebbene possa essere un int su quelli più vecchi.
  • int_least32_t (int_leastX_t): deve essere la dimensione più piccola possibile che possa contenere almeno 32 bit, come 36 bit su un sistema a 36 o 72 bit. Generalmente si associa a int su computer moderni, sebbene possa essere un long su quelli più vecchi.
  • int_fastX_t: deve essere il tipo più veloce possibile in grado di memorizzare almeno X bit. In genere, è la dimensione in Word del sistema se (X <= Word_size) (o talvolta char per int_fast8_t), o si comporta come int_leastX_t se (X > Word_size))
  • intmax_t: deve essere il massimo numero intero supportato dal sistema. Generalmente, sarà almeno di 64 bit sui sistemi moderni, sebbene alcuni sistemi possano supportare tipi estesi più grandi di long long (e in tal caso, intmax_t è necessario per essere il più grande di questi tipi).
  • E altro ancora ...

Meccanicamente, consente all'installatore del compilatore di typedef il tipo appropriato all'identificatore (che sia un tipo standard o un tipo interno con nome scomodo) dietro le quinte, sia creando file di intestazione appropriati, codificandolo nell'eseguibile del compilatore, sia in qualche altro metodo . Ad esempio, su un sistema a 32 bit, Microsoft Visual Studio implementerà il intX_t e tipi simili come segue (nota: commenti aggiunti da me):

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

Su un sistema a 64 bit, tuttavia, potrebbero non essere necessariamente implementati nello stesso modo e posso garantire che non verranno implementati nello stesso modo su un sistema arcaico a 16 bit, presupponendo che sia possibile trovare una versione di MSVS compatibile con uno.

Complessivamente, consente al codice di funzionare correttamente indipendentemente dalle specifiche dell'implementazione e di soddisfare gli stessi requisiti su qualsiasi sistema compatibile con lo standard (ad esempio pid_t può essere garantito abbastanza grande da contenere qualsiasi PID valido sul sistema in questione, no importa quale sistema stai codificando). Inoltre, ti impedisce di conoscere il nocciolo della questione e di dover cercare nomi interni con cui potresti non avere familiarità. In breve, assicura che il tuo codice funzioni allo stesso modo indipendentemente dal fatto che pid_t (o qualsiasi altro typedef simile) sia implementato come int, a short, a long, a long long o anche a __Did_you_really_just_dare_me_to_eat_my_left_shoe__, quindi non devi.


Inoltre, serve come una forma di documentazione, che ti consente di dire a quale variabile è data per colpo d'occhio. Considera quanto segue:

int a, b;

....

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

Ora proviamo di nuovo:

size_t a;
pid_t b;

...

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

Se usato come tale, può aiutare a localizzare segmenti di codice potenzialmente problematici prima che qualcosa si rompa, e può rendere la risoluzione dei problemi molto più semplice di quanto sarebbe altrimenti.

6
Justin Time

Ogni processo nel programma ha un ID di processo specifico. Chiamando pid, conosciamo l'ID assegnato al processo corrente. La conoscenza del pid è estremamente importante quando usiamo fork(), perché restituisce 0 e !=0 valori per le copie figlio e padre in modo ricettivo. Questi due video hanno spiegazioni chiare: video # 1Video # 2

Un esempio: supponiamo di avere il seguente programma 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;
}

Se lo esegui, otterrai 0 per child e non zero/greater than zero per il genitore.

2
user6288471

Una cosa da sottolineare, nella maggior parte delle risposte ho visto qualcosa sulla falsariga di "l'uso di pid_t fa funzionare il codice su sistemi diversi", che non è necessariamente vero.

Credo che la dicitura esatta dovrebbe essere: rende il codice 'compilato' su sistemi diversi

Come, ad esempio, la compilazione del codice su un sistema che usa pid_t a 32 bit produrrà un binario che verrà probabilmente interrotto se eseguito su un altro sistema che utilizza pid_t a 64 bit.

0
0xcurb