Почему getpid () возвращает pid_t вместо int? - PullRequest
48 голосов
/ 11 сентября 2011

Какова логика вызовов типа getpid() , возвращающих значение типа pid_t вместо unsigned int?Или int?Как это помогает?

Я предполагаю, что это связано с переносимостью?Гарантия того, что pid_t имеет одинаковый размер на разных платформах, которые могут иметь разные размеры int s и т. Д .?

Ответы [ 6 ]

41 голосов
/ 11 сентября 2011

Я думаю, что все наоборот: сделать программу переносимой между платформами, независимо от того, является ли, например, PID 16 или 32-битным (или даже более длинным).

34 голосов
/ 11 сентября 2011

Причина состоит в том, чтобы позволить противным историческим реализациям быть по-прежнему совместимыми. Предположим, что ваша историческая реализация имела (довольно распространенное):

short getpid(void);

Конечно, современные системы хотят, чтобы pids были как минимум 32-битными, но если стандарт требует:

int getpid(void);

тогда все исторические реализации, которые использовали short, стали бы несовместимыми. Это было сочтено неприемлемым, поэтому pid_t было создано, и реализации было разрешено определять pid_t в зависимости от того, какой путь предпочтет.

Обратите внимание, что вы ни в коем случае не обязаны использовать pid_t в своем собственном коде, если вы используете тип, достаточно большой для хранения любого pid (например, intmax_t будет работать просто отлично). Единственная причина, по которой pid_t необходимо , заключается в том, что стандарт определяет getpid, waitpid и т. Д. В терминах этого.

9 голосов
/ 11 сентября 2011

На разных платформах и операционных системах разные типы (например, pid_t) могут иметь размер 32 бита (без знака int) на 32-битной машине или 64 бита (без знака длиной) на 64-битной машине. Или, по какой-то другой причине, операционная система может выбрать другой размер. Кроме того, при чтении кода становится ясно, что эта переменная представляет собой «объект», а не просто произвольное число.

7 голосов
/ 22 января 2016

Цель этого состоит в том, чтобы сделать pid_t или любой другой тип сортировки независимым от платформы, так, чтобы он работал должным образом независимо от того, как он на самом деле реализован.Эта практика используется для любого типа, который должен быть независимым от платформы, например:

  • pid_t: должен быть достаточно большим, чтобы хранить PID в системе, для которой вы кодируете.Насколько мне известно, отображается на int, хотя я не очень знаком с библиотекой GNU C.
  • size_t: переменная unsigned, способная хранить результат sizeof оператор.Как правило, по размеру соответствует размеру слова системы, для которой вы кодируете.
  • int16_t (intX_t): должно быть ровно 16 бит, независимо от платформы, и не будет определено дляПлатформы, которые не используют 2 n -битных байтов (обычно 8- или 16-битных) или, что гораздо реже, предоставляют средства доступа ровно 16 битов из более крупного типа (например, PDP).«Байты» -10, которые могут быть любым количеством непрерывных битов из 36-битного слова и, таким образом, могут быть ровно 16 битами), и, таким образом, не поддерживают 16-битные целые типы дополнения до двух (такие как 36-битовая система).Обычно отображается на short на современных компьютерах, хотя может быть int на старых.
  • int_least32_t (int_leastX_t): должен быть наименьшего возможного размера, который может хранить не менее 32биты, такие как 36 бит в 36-битной или 72-битной системе.Как правило, отображается на int на современных компьютерах, хотя на старых может быть long.
  • int_fastX_t: должен быть максимально быстрым типом, который может хранить не менее X бит.Обычно это размер слова системы, если (X <= word_size) (или иногда char для int_fast8_t), или действует как int_leastX_t, если (X > word_size))
  • intmax_t: должен быть максимальным целым числомширина поддерживается системой.Как правило, это будет не менее 64 бит в современных системах, хотя некоторые системы могут поддерживать расширенные типы, размер которых превышает long long (и, если это так, intmax_t должен быть самым большим из этих типов).
  • И еще ...

Механически, это позволяет установщику компилятора typedef соответствующий тип идентификатору (будь то стандартный тип или неуклюже названный внутренний тип) за кулисами, будь тосоздавая соответствующие заголовочные файлы, кодируя их в исполняемый файл компилятора или каким-либо другим способом.Например, в 32-разрядной системе Microsoft Visual Studio будет реализовывать intX_t и аналогичные типы следующим образом (примечание: комментарии, добавленные мной):

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

В 64-разрядной системе, однако, они не обязательно могут быть реализованы одинаково, и я могу гарантировать, что они не будут реализованы одинаково в архаичной 16-битной системе, при условии, что вы можете найти версию MSVS, совместимую с ней.

В целом, это позволяет коду работать должным образом независимо от специфики вашей реализации и соответствовать тем же требованиям в любой совместимой со стандартами системе (например, pid_t может быть достаточно большим, чтобы содержать любой действительный PID в системе ввопрос, независимо от того, какую систему вы кодируете).Это также препятствует тому, чтобы вы знали о мимолетных мелочах и не искали внутренние имена, с которыми вы, возможно, не знакомы.Короче говоря, он гарантирует, что ваш код работает одинаково, независимо от того, реализован ли pid_t (или любой другой подобный typedef) как int, short, long, long long или даже как__Did_you_really_just_dare_me_to_eat_my_left_shoe__, так что вам не нужно.


Кроме того, он служит формой документации, позволяющей с первого взгляда сказать, для чего предназначена данная переменная.Рассмотрим следующее:

int a, b;

....

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

Теперь давайте попробуем это еще раз:

size_t a;
pid_t b;

...

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

Если используется как таковой, он может помочь вам найти потенциально проблемные сегменты кода до того, как что-то сломается, и можетсделать поиск и устранение неисправностей намного проще, чем могло бы быть.

2 голосов
/ 16 июля 2016

Каждый процесс в программе имеет определенный идентификатор процесса.Вызывая pid, мы узнаем назначенный идентификатор текущего процесса. Знание pid исключительно важно, когда мы используем fork(), потому что он возвращает значения 0 и !=0 для дочерних и родительских копий. Эти два видео имеют четкое представлениеобъяснения: видео # 1 видео # 2

Пример: Предположим, у нас есть следующая программа 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;
}

Если вы запустите ее, вы получите 0 для ребенка и не zero/greater than zero для родителя.

0 голосов
/ 15 января 2018

Стоит отметить, что в большинстве ответов я видел что-то вроде «Использование pid_t заставляет код работать на разных системах» , что не обязательно верно.

Я считаю, что точная формулировка должна быть такой: это делает код "компилируемым" в разных системах .

Как, например, компиляция кода в системе, использующей 32-битный pid_t, приведет к созданию двоичного файла, который , вероятно, прекратит работу при запуске в другой системе, использующей 64-битный pid_t.

...