Неэффективны ли языки программирования и методы? (необходимы ассемблер и C)

в течение длительного времени, я думаю и изучаю вывод компилятора языка Си в форме ассемблера, а также архитектуру процессора. Я знаю, что это может быть глупо для вас, но мне кажется, что что-то очень неэффективно. Пожалуйста, не сердитесь, если я ошибаюсь, и я не вижу причин для всех этих принципов. Я буду очень рад, если вы скажете мне, почему он спроектирован таким образом. Я действительно искренне верю, что ошибаюсь, я знаю, что гениальные умы людей, которые собирают ПК, знают причину этого. Что именно, спросите вы? Я скажу вам прямо сейчас, я использую C в качестве примера:

1: Распределение памяти локального объема стека:

Таким образом, для типичного распределения локальной памяти используется стек. Просто скопируйте esp в ebp и выделите всю память через ebp. Хорошо, я бы это понял, если вам явно нужно выделить ОЗУ по умолчанию значения стека, но если я правильно его понимаю, современная ОС использует подкачку в качестве слоя перевода между приложением и физической оперативной памятью, когда адрес, который вы пожелаете, далее переводится до достижения фактической ОЗУ байт. Итак, почему бы просто не сказать, что 0x00000000 - это int a, 0x00000004 - int b и так? И получить к ним доступ только с помощью mov 0x00000000, # 10? Поскольку вы на самом деле не получаете доступ к блокам памяти 0x00000000 и 0x00000004, но те, на которые ваша ОС устанавливают таблицы подкачки. На самом деле, поскольку выделение памяти ebp и esp использует косвенную адресацию, "мой" способ будет еще быстрее.

2: Двукратная переменная распределения:

При запуске приложения Loader загружает свой код в ОЗУ. Когда вы создаете переменную или строку, компилятор генерирует код, который подталкивает эти значения в верхнем стеке при создании в основном. Таким образом, существует фактическая инструкция для этого, и это фактическое число в памяти. Таким образом, в ОЗУ имеется 2 записи одного и того же значения. Один в форме инструкции, второй по форме фактических байтов в ОЗУ. Но почему? Почему бы просто не объявить счетчик переменных, в каком блоке памяти он был бы, чем при использовании, просто вставьте эту ячейку памяти?

Ответ 1

  • Потому что C (и большинство других языков) поддерживают рекурсию, поэтому функция может вызывать себя, и каждому вызову функции нужны отдельные копии любых локальных переменных. Кроме того, на большинстве современных процессоров ваш путь будет на самом деле медленнее - косвенная адресация настолько распространена, что процессоры оптимизированы для него.

  • Кажется, вам нравится поведение C (или, по крайней мере, C) для строковых литералов. Для этого есть хорошие и плохие моменты, такие как тот факт, что даже если вы определили "переменную", вы не можете изменять его содержимое (не влияя на другие переменные, указывающие на одно и то же место).

Ответ 2

Как бы вы реализовали рекурсивные функции? То, что вы описываете, эквивалентно использованию глобальных переменных везде.

Это только одна проблема. Как вы можете ссылаться на предварительно скомпилированный объектный файл и быть уверенным, что он не повредит память ваших процедур?

Ответ 3

Ответы на ваши вопросы в основном завершаются в различной семантике различных классов хранения

  • сегмент данных Google
  • Подумайте о различии в поведении глобальных и локальных переменных.
  • Подумайте о том, как постоянные и непостоянные переменные имеют разные требования, когда функции вызывается повторно (или как говорит Мехрдад, рекурсивно)
  • Подумайте о разнице между статическими и нестационарными автоматическими переменными снова в контексте множественных или рекурсивных вызовов.

Ответ 4

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

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

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

Ответ 5

  • Если каждая функция помещает свою первую переменную со смещением 0 и т.д., вам придется менять отображение памяти каждый раз, когда вы вводите функцию (вы не могли бы выделить все переменные для уникальных адресов, если хотите рекурсию), Это выполнимо, но с текущим оборудованием это очень медленно. Кроме того, преобразование адресов, выполняемое виртуальной памятью, также не является бесплатным, на самом деле довольно сложно реализовать это эффективно.
    Устранение ebp (или любого другого регистра) затрат, имеющих мультиплексор (для выбора регистра) и сумматор (для добавления смещения в регистр). Время, затраченное на это, часто может перекрываться с другими операциями.

  • Если вы хотите изменить статическое значение, вы должны скопировать его в стек. Если вы этого не сделаете (говоря "const" ), то хороший компилятор C не будет копировать его в стек.