Трата памяти? Если main () должна возвращать только 0 или 1, почему main объявляется с int, а не short int или даже char? - PullRequest
6 голосов
/ 11 октября 2019

Например:

#include <stdio.h> 
int main (void)                         /* Why int and not short int? - Waste of Memory */ 
{
     printf("Hello World!");
     return 0; 
}

Почему main() условно определяется с типом int, который выделяет 4 байта в памяти на 32-битной, если обычно возвращает только 0 или 1, тогда как другиетакие типы, как short int (2 байта, 32-битный) или даже char (1 байт, 32-битный), будут более экономить память?

Это тратит пространство памяти.

ПРИМЕЧАНИЕ: вопрос не является дубликатом данной темы;его ответы соответствуют только самому возвращаемому значению, но не его типу данных в явном фокусе.

Вопрос для C и C ++. Если ответы между ними меняются, поделитесь своей мудростью с упоминанием контекста, на котором конкретно сосредоточен язык.

Ответы [ 7 ]

9 голосов
/ 11 октября 2019

Обычно ассемблеры используют свои регистры для возврата значения (например, регистр AX в процессорах Intel). Тип int соответствует машинному слову. То есть не требуется преобразовывать, например, байт, соответствующий типу char, в машинное слово.

И фактически main может возвращать любое целочисленное значение. .

6 голосов
/ 11 октября 2019

Это из-за машины, которой полвека.

В то время, когда был создан C, int было машинным словом на PDP-11 - шестнадцать битов - и это было естественнои эффективно, чтобы main вернул это.

«Машинное слово» было единственным типом в языке B, который Ритчи и Томпсон разработали ранее и из которого выросло C.
Когда C добавил типы, не указав один, дал вам машинуслово - int.
(в то время было очень важно сэкономить место, поэтому не требуется указывать наиболее распространенный тип - очень хорошая вещь.)

Итак, посколькуПрограмма B началась с

main()

, и программисты, как правило, консервативны по языку, C сделал то же самое и вернул int.

5 голосов
/ 11 октября 2019

Есть две причины, по которым я не считаю это пустой тратой:

1 практическое использование 4-байтового кода выхода

Если вы хотите вернуть код выхода, который точно описывает ошибку, которую вы хотитеболее 8 бит.

В качестве примера вы можете сгруппировать ошибки: первый байт может описывать неопределенный тип ошибки, второй байт может описывать функцию, вызвавшую ошибку, третий байт может давать информацию о причине ошибки. error и четвертый байт описывают дополнительную отладочную информацию.

2 Padding

Если вы передаете single short или char, они все равно будут выровнены, чтобы соответствовать машинному слову,который часто составляет 4 байта / 32 бита в зависимости от архитектуры. Это называется заполнением и означает, что вам, скорее всего, все еще понадобится 32-битная память для возврата одиночного шорта или символа.

3 голосов
/ 11 октября 2019

Старомодное соглашение с большинством оболочек состоит в том, чтобы использовать наименее значимые 8 битов int, а не только 0 или 1. 16 битов все чаще встречаются из-за минимального размера int, разрешенногостандарт.

А что за проблема с потерей места? Это пространство действительно впустую? Ваш компьютер настолько полон "вещей", что оставшиеся sizeof(int) * CHAR_BIT - 8 будут иметь значение? Может ли архитектура использовать это и использовать эти оставшиеся биты для чего-то еще? Я очень сильно сомневаюсь в этом.

Так что я бы не сказал, что память вообще потрачена впустую, поскольку вы возвращаете ее из операционной системы после завершения программы. Возможно экстравагантно ? Немного похоже на использование большого бокала для небольшого напитка?

2 голосов
/ 11 октября 2019

1-й: Только ваше предположение / утверждение if it usually returns only 0 or 1 неверно.

Обычно ожидается, что код возврата будет 0, если не было ошибок, но в противном случае он может вернуть любое число, представляющее разные ошибки. И большинство (по крайней мере, программы командной строки) делают это. Многие программы также выводят отрицательные числа.

Однако есть несколько распространенных используемых кодов https://www.tldp.org/LDP/abs/html/exitcodes.html и здесь другой член SO указывает на заголовок Unix, который содержит некоторые коды https://stackoverflow.com/a/24121322/2331592

Так ведьэто не просто вещь типа C или C++, но также есть исторические причины того, как большинство операционных систем работают и ожидают, что программы будут вести себя, и так как языки должны это поддерживать, и, по крайней мере, языки C делают этос помощью int main(...).

2-й: ваш вывод It is wasting memory space неверен.

  1. Использование int по сравнению с более коротким типом не требует каких-либо отходов. Память обычно обрабатывается в размере слова (это может означать, что это может зависеть от вашей архитектуры) в любом случае
  2. работа с типами подслов включает в себя перегруженные вычисления в некоторых архитектурах (читай: загрузка, слово, маскировка несвязанных битов;сохранить: загрузить память, замаскировать переменные биты или их с новым значением, записать слово обратно)
  3. память не тратится впустую, если вы не используете его. если вы напишите return 0;, то на этом этапе память никогда не будет использоваться. если вы return myMemorySaving8bitVar; используете только 1 байт (наиболее вероятно в стеке (если не оптимизированы вообще))
1 голос
/ 11 октября 2019

Вы либо работаете в C, либо изучаете C, так что я думаю, что это действительно хорошая идея, что вы заинтересованы в эффективности. Тем не менее, кажется, что есть несколько вещей, которые, кажется, нуждаются в разъяснении здесь.

Во-первых, тип данных int никогда не предназначался для обозначения «32 бита». Идея заключалась в том, что int будет наиболее естественным двоичным целочисленным типом на целевой машине - обычно это размер регистра.

Во-вторых, возвращаемое значение из main () предназначено для широкого диапазона реализаций. на разных операционных системах. Система POSIX использует 8-битный код возврата без знака. В Windows используются 32-разрядные биты, которые интерпретируются оболочкой CMD как дополнение к 2 со знаком. Другая ОС может выбрать что-то другое.

И, наконец, если вас беспокоит «потеря памяти», это проблема реализации, которая в данном случае даже не проблема. Коды возврата из main обычно возвращаются в машинных регистрах, а не в памяти, поэтому нет затрат или экономии. Даже если бы это было так, сохранение 2 байтов в ходе выполнения нетривиальной программы не стоило бы никакого времени для разработчика.

1 голос
/ 11 октября 2019

Ответ «потому что обычно не возвращает только 0 или 1». Я нашел эту ветку от сообщества разработчиков программного обеспечения, которая хотя бы частично отвечает на ваш вопрос. Вот два основных момента, первый из принятых ответов:

Целое число дает больше места, чем байт, для сообщения об ошибке. Он может быть перечислен (возврат 1 означает XYZ, возврат 2 означает ABC, возврат 3, означает DEF и т. Д.) Или использоваться в качестве флагов (0x0001 означает, что произошел сбой, 0x0002 означает, что произошел сбой, 0x0003значит и то и то не получилось). Ограничение всего лишь одним байтом может легко исчерпать флаги (только 8), поэтому решение, вероятно, заключалось в использовании целого числа.

Интересный момент также поднимает Кейт Томпсон :

Например, на диалекте C, используемом в Plan 9 операционная система main обычно объявляется как функция void, но статус выходавозвращается в вызывающую среду, передавая строковый указатель в функцию exits(). Пустая строка обозначает успех, а любая непустая строка обозначает какой-то сбой. Это может быть реализовано, если main вернуть char* результат.

Вот еще один интересный момент из форума unix.com :

(Некоторые из перечисленных ниже могут быть специфичными для x86.)

Возвращаясь к первоначальному вопросу: где хранится статус выхода? Внутри ядра.

Когда вы вызываете exit (n), младшие 8 битов целого числа n записываются в регистр процессора. Реализация системного вызова ядра затем скопирует его в связанную с процессом структуру данных.

Что если ваш код не вызывает exit ()? Библиотека времени выполнения c, ответственная за вызов main (), будет вызывать exit () (или какой-либо его вариант) от вашего имени. Возвращаемое значение main (), которое передается в среду выполнения c в регистре, используется в качестве аргумента для вызова exit ().

Относится к последней цитате, вот еще один из cppreference.com

5) Выполнение возврата (или неявного возврата по достижении конца main) эквивалентно первому выходу из функции в обычном режиме (что уничтожает объекты с помощью автоматическогодлительность хранения), а затем вызывать std :: exit с тем же аргументом, что и аргумент возврата. (затем std :: exit уничтожает статические объекты и завершает программу)

Наконец, я нашел этот действительно крутой пример здесь (хотя автор поста ошибочно говорит, чтовозвращенный результат является возвращаемым значением по модулю 512). После компиляции и выполнения следующего:

int main() {
    return 42001;
}

на POSIX-совместимой моей * системе echo $? возвращает 17. Это потому, что 42001 % 256 == 17, который показывает, что 8 бит данныхна самом деле используется. Имея это в виду, выбор int гарантирует, что достаточно места для передачи информации о состоянии завершения программы, потому что согласно этому ответу , соответствие стандарту C ++ гарантирует, что размер int (вбиты)

не может быть меньше 8. Это потому, что он должен быть достаточно большим, чтобы содержать «восьмибитные кодовые единицы формы кодировки Unicode UTF-8».

РЕДАКТИРОВАТЬ:

* Как Эндрю Хенле указал в комментарии:

Полностью POSIX-совместимая система делает все int возвращаемое значениедоступно, а не только 8 бит. См. pubs.opengroup.org / onlinepubs / 9699919799 / basedefs / signal.h.html : «Если si_code равно CLD_EXITED, то si_status содержит выходное значение процесса; в противном случае, он равен сигналу, который заставил процесс изменить состояние. Выходное значение в si_status должно быть равным полному выходному значению (то есть значение, переданное _exit(), _Exit() или exit()или возвращено из main()); оно не должно быть ограничено младшими восемью битами значения. "

Думаю, это еще более веский аргумент в пользу использования int для типов данных меньшего размера.

...