Поймите, что почти все, что вы делаете, приведет к чтению чисел ЦП с некоторого адреса памяти, выполнению некоторого вычисления или записи их по какому-либо адресу памяти.
Таким образом, большая часть общения с внешним миром - такими устройствами, как ваша видеокарта, сетевая карта и т. Д. - в основном сводится к чтению или записи в области волшебной памяти.
(Это небольшое упрощение, есть несколько других вещей, которые может делать ЦП - порты ввода-вывода, в которые он может читать / записывать числа и т. Д .; они не доступны напрямую из стандартного C, и, как правило, библиотеки C, которые предоставляют такой функционал будет иметь соответствующий код, написанный на ассемблере, но давайте сейчас его выполним).
Аппаратные драйверы, написанные на C, обычно объявляют struct
s, которые описывают расположение отображаемых в памяти областей, используя знакомые типы C, получают адреса соответствующих областей, выполняют соответствующие приведения, а затем просто используют полученные указатели, как и любые другие. .
ОС обычно оборачивает этот аппаратно-специфический код в какой-то механизм, обеспечивающий виртуализацию (так что ваш код может притвориться, что он разговаривает с каким-то стандартным идеализированным устройством, и ОС переводит между этим и тем, что на самом деле находится в вашем машина) и разделение привилегий (поэтому ваш код не может делать то, что ему не нужно, и / или не нарушает код других людей). Таким образом, библиотеки, на которые вы ссылаетесь, не будут напрямую взаимодействовать с оборудованием; они будут вызывать операционную систему (обычно используя какой-либо механизм системного вызова / прерывания / исключения), который сделает это для них. Но сама ОС будет делать примерно то, что я описал выше.