Как большинство встроенных компиляторов C определяют символы для ввода / вывода с отображением памяти?

Я часто пишу так называемые выводы ввода / вывода памяти, подобные этому

P3OUT |= BIT1; 

Я предположил, что P3OUT заменяют что-то вроде этого моим препроцессором:

 *((unsigned short *) 0x0222u) 

Но сегодня я ворвался в файл H и увидел что-то в этом роде:

  volatile unsigned short P3OUT @ 0x0222u; 

До этого происходит еще некоторое расширение, но, как правило, это происходит. Используется символ «@». Выше того, что есть некоторые # прагмы об использовании расширенного набора языка C. Я предполагаю, что это какая-то директива для компоновщика, и фактически символ определяется как находящийся в этом месте на карте памяти.

Было ли мое предположение правильным, что происходит в большинстве случаев у большинства компиляторов? Имеет ли это значение так или иначе? Откуда взялось это обозначение @, это какой-то стандарт?

Я использую IAR Embedded workbench.

Этот вопрос аналогичен этому: как поместить переменную в данный абсолютный адрес в памяти (с GCC) . Это соответствует тому, что я предполагал, что мой компилятор все равно.

Хотя выражение типа (unsigned char *)0x1234 на многих компиляторах дает указатель на аппаратный адрес 0x1234, ничто в стандарте не требует какой-либо конкретной связи между целым числом, которое передается указателю и результирующему адресу. Единственное, что специфицирует стандарт, это то, что если конкретный целочисленный тип не меньше, чем intptr_t , и приведение указателя к этому конкретному типу дает некоторое значение, то приведение этого конкретного значения обратно к исходному типу указателя даст эквивалент указателя к оригиналу.

Компилятор IAR предлагает нестандартное расширение, которое позволяет компилятору запрашивать, чтобы переменные размещались по указанным жестко закодированным адресам. Это дает некоторые преимущества по сравнению с использованием макросов для создания выражений указателя. Во-первых, это гарантирует, что такие переменные будут синтаксически рассматриваться как переменные; в то время как выражения pointer-kludge обычно интерпретируются правильно, если они используются в законном коде, возможно, для нелегитимного кода, который должен завершиться ошибкой компиляции, чтобы скомпилировать, но произвести нечто иное, чем желаемый эффект. Кроме того, синтаксис IAR определяет символы, доступные для компоновщика, и поэтому может использоваться в модулях на языке сборки. Напротив, файл .H, который определяет macros указателя-kludge, не будет использоваться в модуле на языке ассемблера; любое оборудование, которое будет использоваться как в коде C, так и в сборе, должно указывать адрес в двух отдельных местах.

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

 volatile unsigned short P3OUT @ 0x0222u; 

Является распространенным способом размещения переменной по фиксированному адресу. Но вы также увидите, что он используется для идентификации отдельных битов в ячейке с отображением памяти = особенно для микроcontrollerов, которые имеют битовые инструкции, такие как семейства ПОС.

Это те вещи, которые C-стандарт не адресует, и должен IMHO, поскольку небольшие встроенные микроcontrollerы в конечном итоге станут основным рынком для C (да, я знаю, что kernel ​​написано на C, но много материала для пользовательского пространства переход на C ++).

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

Аналогичная область объявляет функцию ISR.

В этом документе показан один из подходов, которые мы рассмотрели