Как язык расширяет себя? [закрыто]

208

Я изучаю C ++, и я только начал изучать некоторые возможности Qt для программирования программ с графическим интерфейсом. Я задал себе следующий вопрос:

Как C ++, который ранее не имел синтаксиса, способного запрашивать у ОС окно или способ связи через сети (с API, которые я не совсем понимаю, я признаю), внезапно получил такие возможности через библиотеки, написанные на C ++? Мне все кажется ужасно круглым. Какие инструкции C ++ вы могли бы придумать в этих библиотеках?

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

Мед Ларби Сентисси
источник
27
Как std :: cout вообще что-то рисует на мониторе? Или он находится поверх компилятора, который понимает ваше оборудование?
doctorlove
14
Отличный вопрос В конечном итоге трудно ответить, пока вы не изучите аппаратное обеспечение.
user541686
17
Qt не является расширением языка (для этого потребуется компилятор, поддерживающий Qt). Это просто библиотека, которая добавлена ​​в ваш арсенал. В конце концов, на самом низком уровне все библиотеки взаимодействуют с ОС через системные вызовы, которые не зависят от языка, но очень сильно зависят от ОС и архитектуры процессора.
DevSolar
8
afaik, C ++ имеет встроенную сборку, которая может делать практически все что угодно
отображаемое имя
9
@DevSolar: На самом деле Qt расширяет язык благодаря собственному механизму слота сигнала, отражению и многим другим динамическим функциям. И эти вещи требуют компилятора (компилятор мета-объекта) для компиляции до кода C ++.
Сиюань Рен

Ответы:

194

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

В случае, например, Windows, операционная система предоставляет так называемый WIN32 API для приложений, работающих в Windows. Библиотека Qt использует этот API для предоставления приложениям, использующим Qt, свой собственный API. Вы используете Qt, Qt использует WIN32, WIN32 использует более низкие уровни операционной системы Windows и так далее, пока не появятся электрические сигналы в оборудовании.

Какой-то программист чувак
источник
56
Примечание: Qtздесь приведена абстракция нижележащего слоя, потому что в Linux Qtвызывается API Linux, а не WIN32 API.
Матье М.
5
Вероятно, я бы немного подробнее остановился на примере Qt, который просто появляется, как будто он легко расширяет возможности c ++. Когда реальность такова, они прикладывают много усилий, чтобы создать общий API, (с сомнением) много разных «луковых ядер». Это те, которые обеспечивают мобильность поверх нестандартных нестандартных бэкэндов.
luk32
81
Компьютер похож на лук: прорезая его, ты плачешь, но потом он несколько вкуснее.
alecov
3
@ChristopherPfohl Да, пришлось использовать его, так как я не мог понять, как компьютер будет похож на коробку конфет. :)
Какой-то программист чувак
1
@Celeritas учитель, вероятно, сказал user32.dll, или возможно gdi32.dll.
user253751
59

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

Но библиотеки не должны быть написаны на C ++, чтобы их можно было использовать в программе на C ++. Даже если они написаны на C ++, они могут использовать другие библиотеки, не написанные на C ++. Так что тот факт, что C ++ не предоставил никакого способа сделать это, не препятствует его добавлению, если есть какой-то способ сделать это вне C ++.

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


источник
Вы имеете в виду, что эти библиотеки, написанные на других языках, уже скомпилированы с использованием других компиляторов? И тогда должен быть какой-то интерфейсный файл, связывающий каждый вызов функции, предоставляемый C ++ библиотекой, с предварительно скомпилированной версией библиотеки? Таким образом, позволяя компилятору C ++ знать, во что переводить эти вызовы?
Мед Ларби Сентисси
2
@MedLarbiSentissi 1) Не обязательно другие компиляторы. Возможно (и это часто бывает), что один единственный компилятор способен компилировать несколько языков, включая ассемблер, и даже может компилировать C ++ с помощью встроенной сборки. 2) В зависимости от конкретной системы и компилятора, сделать эти функции вызываемыми из C ++ действительно можно с помощью какого-либо файла интерфейса, но этот тип файла интерфейса уже может быть заголовком C (или даже C ++), непосредственно используемым из C ++.
1
@MedLarbiSentissi: Многие библиотеки Windows скомпилированы в dll-файлы, которые содержат как собственный интерфейс, так и код. Вы можете заглянуть в DLL и увидеть список функций, которые он позволяет вам использовать. Они также часто поставляются с заголовочным файлом C. Когда вы создаете свой exe-файл, он содержит список библиотек, которые ему нужны для запуска. Когда операционная система пытается загрузить ваш exe-файл, она также автоматически загружает эти библиотеки перед началом выполнения.
Mooing Duck
8
Этот ответ, по-видимому, предполагает, что «магия» полностью лежит в других вызываемых языках, но на самом деле большая часть кода , составляющего большинство современных операционных систем, - это C (только с очень аппаратно-связанными или критичными для производительности деталями, написанными на ассемблере) - и определенно возможно использовать C ++ вместо этого. Дело в том, что «волшебства» не существует, создаются языки для создания таких мощных абстракций, и как только вы можете взаимодействовать с оборудованием, возможности практически безграничны.
Matteo Italia
1
@hvd Я думаю, что весь конфликт в этом обсуждении состоит в том, что вы (и другие) определяете C как функции, которые для него указаны. Фактически, компиляторы добавляют намного больше, чем указано, что делает вопрос о том, что C является довольно нетривиальным для ответа. Для меня особенность языка (а значит, и того, что он есть) - это мета-способ выражения потока программы и возможности структурирования. Структурированные элементы для него не важны, так как это просто более приятный ASM-код, который может быть добавлен компиляторами по их желанию
LionC
43

C и C ++ имеют 2 свойства, которые позволяют всю эту расширяемость, о которой говорит OP.

  1. C и C ++ могут получить доступ к памяти
  2. C и C ++ могут вызывать ассемблерный код для инструкций не на языке C или C ++.

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

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

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

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

Win32 API обертывают некоторые графические функции общим набором виджетов платформы. Qt продвигается дальше, оборачивая Win32 (или X Windows) API кроссплатформенным способом.

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

Дорон
источник
Предостережение о # 2: C и C ++ могут только реально вызывать функции, которые придерживаются «соглашения о вызовах», которое компилятор понимает и ожидает. (Код ассемблера может использовать любое соглашение, которое ему нравится, или даже вообще ничего - поэтому код может не вызываться напрямую.) К счастью, каждый уважающий себя компилятор предоставляет встроенный способ использования общих соглашений платформы. (Компиляторы Windows C, например, позволяют использовать / использовать функции, использующие соглашения "cdecl", "stdcall" или "fastcall".) Но код ассемблера должен использовать соглашение, известное компилятору, или C и C ++ могут ' не могу назвать это напрямую.
chao
2
Кроме того, отображение ввода-вывода с отображением в памяти является обычным явлением, но не всей историей. Например, ПК обычно обращаются к последовательным портам, дискам и т. Д., Используя «порты ввода-вывода» в x86 - совершенно другой механизм. (Видеобуфер обычно отображается в памяти, но режимы видео и т. Д. Обычно управляются через порты ввода / вывода.)
cHao
@cHao: Конечно, классический подход, использующий INP и OUTP, вытесняется в пользу DMA; поколение PCI, кажется, делает больше с регистрами специальных функций с отображением в памяти, теперь, когда есть способ автоматически сопоставлять устройства с неперекрывающимися областями и обнаруживать их с помощью драйверов, и меньше с портами ввода / вывода.
Бен Фойгт
современные периферийные устройства будут использовать DMA для массовой передачи данных, но вы все равно будете программировать контроллер DMA с адресуемой памятью
doron
@doron: Хмм, вы программируете контроллер DMA через адресное пространство ввода-вывода (а не пространство памяти) на ПК, по крайней мере, если вы в здравом уме. Современные процессоры x86 любят переупорядочивать доступ к памяти для повышения производительности. С MMIO это может иметь катастрофические последствия ... поэтому вам нужно быть осторожным, чтобы эти адреса не были кешированы, а инструкции по сериализации помещались во все нужные места. OTOH, сам x86 гарантирует, что чтение и запись в пространство ввода / вывода выполняются в программном порядке. Вот почему большая часть важных вещей все еще выполняется через пространство ввода / вывода (которое обычно не доступно через указатель), и, вероятно, всегда будет.
Чао
23

Языки (например, C ++ 11 ) - это спецификации на бумаге, обычно написанные на английском языке. Загляните в последнюю версию C ++ 11 (или купите дорогостоящую спецификацию у вашего поставщика ISO).

Обычно вы используете компьютер с какой-либо языковой реализацией (в принципе, вы можете запустить программу на C ++ без какого-либо компьютера, например, используя для интерпретации несколько рабов-людей; это было бы неэтично и неэффективно)

Ваша реализация C ++ в целом работает над некоторой операционной системой и взаимодействует с ней (используя некоторый специфичный для реализации код, часто в какой-то системной библиотеке). Обычно эта связь осуществляется через системные вызовы . Посмотрите, например, в syscalls (2) список системных вызовов, доступных в ядре Linux .

С прикладной точки зрения системный вызов - это элементарная машинная инструкция, подобная SYSENTERx86-64, с некоторыми соглашениями ( ABI ).

На моем рабочем столе Linux библиотеки Qt выше клиентских библиотек X11, взаимодействующих с сервером X11 через протоколы Xorg через X Windows .

В Linux используйте lddсвой исполняемый файл, чтобы увидеть (длинный) список зависимостей от библиотек. Используйте pmapв своем рабочем процессе, чтобы увидеть, какие из них «загружены» во время выполнения. Кстати, в Linux ваше приложение, вероятно, использует только бесплатное программное обеспечение, вы можете изучить его исходный код (от Qt до Xlib, libc, ... ядра), чтобы лучше понять, что происходит

Василий Старынкевич
источник
2
Для справки, ANSI продает спецификацию C ++ 11 по чуть менее возмутительной цене в 60 долларов США. (Раньше это было вдвое меньше, но инфляция.: P) Он помечен как INCITS / ISO / IEC 14882, но это, по крайней мере, те же базовые спецификации, которые предлагает ISO. Не уверен насчет ошибок / TR.
Чао
19

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

Системные вызовы - это низкоуровневый способ использования возможностей операционной системы, но он может быть сложным и громоздким в использовании, поэтому его часто «оборачивают» в API, чтобы вам не приходилось иметь с ними дело напрямую. Но под всем, что бы вы ни делали, включая ресурсы, связанные с O / S, будут использоваться системные вызовы, включая печать, сетевые подключения, сокеты и т. Д.

В случае Windows Microsoft Windows имеет свой GUI, фактически записанный в ядро, поэтому существуют системные вызовы для создания окон, рисования графики и т. Д. В других операционных системах GUI может не являться частью ядра, и в этом случае насколько я знаю, не было бы никаких системных вызовов для вещей, связанных с GUI, и вы могли бы работать только на еще более низком уровне с любой доступной графикой низкого уровня и входными связанными вызовами.

Дейв Кузино
источник
3
Важно, что эти системные вызовы отнюдь не волшебство. Они обслуживаются ядром, которое обычно написано на C (++). Более того, системные вызовы даже не нужны. В элементарной ОС без защиты памяти окна можно рисовать, помещая пиксели непосредственно в аппаратный кадровый буфер.
el.pescado
15

Хороший вопрос. Каждый новый разработчик C или C ++ имеет это в виду. Я предполагаю стандартную машину x86 для остальной части этого поста. Если вы используете компилятор Microsoft C ++, откройте блокнот и введите его (назовите файл Test.c)

int main(int argc, char **argv)
{
   return 0
}

А теперь скомпилируйте этот файл (используя командную строку разработчика) cl Test.c /FaTest.asm

Теперь откройте Test.asm в своем блокноте. Вы видите переведенный код - C / C ++ переведен на ассемблер. Ты понял намек?

_main   PROC
    push    ebp
    mov ebp, esp
    xor eax, eax
    pop ebp
    ret 0
_main   ENDP

Программы на C / C ++ предназначены для работы на металле. Это означает, что они имеют доступ к оборудованию более низкого уровня, что облегчает использование возможностей оборудования. Скажем, я собираюсь написать библиотеку C getch () на компьютере с архитектурой x86.

В зависимости от ассемблера я мог бы напечатать что-нибудь таким образом:

_getch proc 
   xor AH, AH
   int 16h
   ;AL contains the keycode (AX is already there - so just return)
ret

Я запускаю его с помощью ассемблера и генерирую .OBJ - назовите его getch.obj.

Затем я пишу программу на C (я ничего не включаю)

extern char getch();

void main(int, char **)
{
  getch();
}

Теперь назовите этот файл - GetChTest.c. Скомпилируйте этот файл, передав getch.obj. (Или скомпилировать по отдельности в .obj и LINK GetChTest.Obj и getch.Obj вместе, чтобы создать GetChTest.exe).

Запустите GetChTest.exe, и вы обнаружите, что он ожидает ввода с клавиатуры.

Программирование на C / C ++ - это не только язык. Чтобы быть хорошим программистом на C / C ++, вы должны хорошо понимать тип машины, на которой он работает. Вам нужно будет знать, как осуществляется управление памятью, как структурированы регистры и т. Д. Возможно, вам не понадобится вся эта информация для обычного программирования, но они очень вам помогут. Помимо базовых знаний об оборудовании, это, безусловно, поможет, если вы поймете, как работает компилятор (то есть, как он переводит) - что может позволить вам настроить свой код по мере необходимости. Это интересная упаковка!

Оба языка поддерживают ключевое слово __asm, что означает, что вы также можете смешивать код на ассемблере. Изучение C и C ++ сделает вас лучшим программистом в целом.

Нет необходимости всегда связываться с Ассемблером. Я упоминал об этом, потому что думал, что это поможет вам лучше понять. В основном, большинство таких библиотечных вызовов используют системные вызовы / API, предоставляемые операционной системой (операционная система, в свою очередь, выполняет взаимодействие с оборудованием).

Кришна Сантош Сампатх
источник
10

Как C ++ ... вдруг получает такие возможности через библиотеки, написанные на C ++?

Нет ничего волшебного в использовании других библиотек. Библиотеки - это простые большие пакеты функций, которые вы можете вызывать.

Считайте, что вы пишете такую ​​функцию

void addExclamation(std::string &str)
{
    str.push_back('!');
}

Теперь, если вы включите этот файл, вы можете написать addExclamation(myVeryOwnString);. Теперь вы можете спросить: «Как в C ++ вдруг появилась возможность добавлять восклицательные знаки в строку?» Ответ прост: вы написали функцию для этого, а затем вызвали ее.

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

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

Филипп
источник
8

Ключ - это возможность операционной системы предоставлять API и подробное описание того, как использовать этот API.

Операционная система предлагает набор API с соглашениями о вызовах. Соглашение о вызовах определяет способ, которым параметр передается в API, и как возвращаются результаты, и как выполнить фактический вызов.

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

THST
источник
7

Нет необходимости в специальном синтаксисе для создания окон. Все, что требуется, - это то, что ОС предоставляет API для создания окон. Такой API состоит из простых вызовов функций, для которых C ++ предоставляет синтаксис.

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

Также следует отметить, что Qt является плохим примером, поскольку он использует так называемый мета-компилятор для расширения синтаксиса C ++. Это, однако, не связано с его способностью вызывать API, предоставляемые ОС, чтобы фактически рисовать или создавать окна.

Джо
источник
7

Во-первых, немного недоразумений, я думаю,

Как работает C ++, который ранее не имел синтаксиса, способного запрашивать у ОС окно или способ связи через сети

Нет синтаксиса для выполнения операций ОС. Это вопрос семантики .

вдруг получить такие возможности через библиотеки, написанные на C ++ сами

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

Вот хорошее руководство по этому вопросу: http://www.win.tue.nl/~aeb/linux/lk/lk-4.html
Это для Linux, но принципы те же.

Как операционная система выполняет операции с графическими картами, сетевыми картами и т. Д.? Это очень широкая тема, но в основном вам нужен доступ к прерываниям, портам или записи некоторых данных в специальную область памяти. Поскольку эти операции защищены, вам все равно нужно вызывать их через операционную систему.

Дунайский моряк
источник
7

В попытке представить несколько иной взгляд на другие ответы я отвечу так.

(Отказ от ответственности: я немного упрощаю вещи, ситуация, которую я представляю, является чисто гипотетической и написана как средство демонстрации концепций, а не на 100% верная жизни).

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

Во-первых, поскольку C ++ компилируется в машинный код, вам необходимо определить способ использования машинного кода для взаимодействия с C ++. Здесь функции приходят, функции принимают аргументы и возвращают значения, таким образом, они обеспечивают стандартный способ передачи данных между различными разделами кода. Они делают это, создавая нечто, известное как соглашение о вызовах .

А соглашение о вызовах государства , где и как аргументы должны быть размещены в памяти , так что функция может найти их , когда он запускается на выполнение. Когда функция вызывается, вызывающая функция помещает аргументы в память, а затем просит ЦПУ перейти к другой функции, где она делает то, что делает, прежде чем вернуться к тому месту, откуда она была вызвана. Это означает, что вызываемый код может быть абсолютно любым, и это не изменит способ вызова функции. В этом случае, однако, код функции должен относиться к операционной системе и работать во внутреннем состоянии операционной системы.

Итак, спустя много месяцев, и у вас все функции ОС разобраны. Ваш пользователь может вызывать функции для создания окон и рисования на них, они могут создавать темы и всякие замечательные вещи. Но вот в чем проблема, функции вашей ОС будут отличаться от функций Linux или Windows. Таким образом, вы решаете, что вам нужно предоставить пользователю стандартный интерфейс, чтобы он мог писать переносимый код. Вот где приходит QT.

Как вы почти наверняка знаете, в QT есть множество полезных классов и функций для выполнения задач, которые делают операционные системы, но способом, который кажется независимым от базовой операционной системы. Это работает так, что QT предоставляет классы и функции, которые одинаковы в том виде, в котором они отображаются пользователю, но код этих функций различен для каждой операционной системы. Например, QT QApplication :: closeAllWindows () будет фактически вызывать специализированную функцию закрытия окна каждой операционной системы в зависимости от используемой версии. В Windows он, скорее всего, будет вызывать CloseWindow (hwnd), тогда как в ОС, использующей X Window System, он потенциально будет вызывать XDestroyWindow (display, window).

Как видно, операционная система имеет много уровней, каждый из которых должен взаимодействовать через интерфейсы многих разновидностей. Есть много аспектов, которые я даже не затронул, но объяснение их всех заняло бы очень много времени. Если вас больше интересует внутренняя работа операционных систем, я рекомендую проверить OS dev wiki .

Однако имейте в виду, что причина, по которой многие операционные системы предпочитают предоставлять интерфейсы для C / C ++, заключается в том, что они компилируются в машинный код, они позволяют смешивать инструкции по сборке со своим собственным кодом и предоставляют большую степень свободы программисту.

Опять же, здесь много чего происходит. Я хотел бы продолжить, чтобы объяснить, как библиотеки, такие как .so и .dll файлы не должны быть написаны на C / C ++ и могут быть написаны на ассемблере или других языках, но я чувствую, что если я добавлю больше, я мог бы также написать целую статью, и как бы мне этого не хотелось, у меня нет сайта для ее размещения.

Pharap
источник
6

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

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

user541686
источник
4
На самом деле системный вызов не является инструкцией процессора и не имеет ничего общего с внутренними функциями. Это скорее функция ядра операционной системы, которое связывается с устройствами.
MatthiasB
3
@MatthiasB: Ну, вы не правы, так как syscall(и его двоюродный брат sysenter) действительно инструкция процессора.
user541686
2
Это был просто намек на улучшение вашего ответа, так как он не был понятен для меня. Не воспринимайте это как личную атаку или что-то в этом роде.
MatthiasB
1
@MatthiasB: Я не принимаю это на свой счет. Я говорю, что уже знаю, что ответ на самом деле не является точным на 100%, но я думаю, что это достаточно хорошее упрощение, чтобы ответить на ОП - поэтому, если вы действительно знаете способ написать лучший ответ, пожалуйста, напишите свой ответь или найди время, чтобы отредактировать мой. Мне действительно нечего добавить, что, я думаю, стоит того, поэтому, если вы хотите увидеть что-то лучшее на этой странице, вам придется приложить усилия самостоятельно.
user541686
3
Системные вызовы выполняются с использованием программных прерываний. Подобные инструкции sysenterявляются оптимизированными путями вызовов, поскольку переключение контекста, используемое обработчиками прерываний, было не таким быстрым, как всем хотелось бы, но, по сути, это все еще программно сгенерированное прерывание, в то время как оно обрабатывается путем векторизации в обработчик, установленный ядром ОС. Часть процесса переключения контекста, который выполняется IS, sysenterзаключается в изменении битов режима в процессоре, чтобы установить кольцо 0 - полный доступ ко всем привилегированным инструкциям, регистрам и областям памяти и ввода-вывода.
Бен Фойгт
4

Ваша программа на C ++ использует библиотеку Qt (также написанную на C ++). Библиотека Qt будет использовать функцию Windows CreateWindowEx (которая была написана на C внутри kernel32.dll). Или в Linux он может использовать Xlib (также написанный на C), но он также может посылать необработанные байты, которые в протоколе X означают « Пожалуйста, создайте окно для меня ».

С вашим вопросом catch-22 связано историческое примечание о том, что «первый компилятор C ++ был написан на C ++», хотя на самом деле это был компилятор C с несколькими понятиями C ++, достаточно, чтобы он мог скомпилировать первую версию, которая затем могла скомпилировать себя ,

Аналогично, компилятор GCC использует расширения GCC: сначала он компилируется в версию, а затем используется для перекомпиляции. (Инструкции по сборке GCC)

Анхель
источник
2

Как я вижу вопрос, это на самом деле вопрос компилятора.

Посмотрите на это так, вы пишете кусок кода на ассемблере (вы можете сделать это на любом языке), который переводит ваш вновь написанный язык, который вы хотите назвать Z ++, в ассемблер, для простоты давайте назовем его компилятором (это компилятор) ,

Теперь вы даете этому компилятору некоторые базовые функции, чтобы вы могли писать int, string, arrays и т. Д. На самом деле вы предоставляете ему достаточно возможностей, чтобы вы могли писать сам компилятор на Z ++. и теперь у вас есть компилятор для Z ++, написанный на Z ++, довольно аккуратно, верно.

Что еще круче, так это то, что теперь вы можете добавлять способности к этому компилятору, используя уже имеющиеся у него возможности, таким образом расширяя язык Z ++ новыми функциями, используя предыдущие функции.

Например, если вы напишите достаточно кода, чтобы нарисовать пиксель любого цвета, вы можете расширить его, используя Z ++, чтобы нарисовать все, что вы захотите.

Томас Андре Ван
источник
0

Аппаратное обеспечение - это то, что позволяет этому случиться. Вы можете думать о графической памяти как о большом массиве (состоящем из каждого пикселя на экране). Чтобы нарисовать на экране, вы можете написать в эту память, используя C ++ или любой другой язык, который позволяет прямой доступ к этой памяти. Эта память просто доступна или находится на видеокарте.

В современных системах прямой доступ к графической памяти потребует написания драйвера из-за различных ограничений, поэтому вы используете косвенные средства. Библиотеки, которые создают окно (на самом деле просто изображение, как любое другое изображение), а затем записывают это изображение в графическую память, которая затем отображается на экране графическим процессором. Ничего не нужно добавлять к языку, кроме возможности записи в определенные области памяти, для чего нужны указатели.

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