Как мы можем использовать союзы и структуру внутри оператора #define - PullRequest
0 голосов
/ 06 февраля 2019

Я просматривал заголовочный файл микроконтроллера, когда нашел это,

 #define DEFA(name, address) __no_init union \
{ \
  struct \
  { \
    volatile unsigned char  name##_L; \
    volatile unsigned char  name##_H; \
  }; \
  struct \
  { \
    volatile unsigned short name##L; \
    volatile unsigned short name##H; \
  }; \
  __ACCESS_20BIT_REG__ name; \
} @ address;

У меня есть несколько вопросов здесь,

  1. Я не зналчто мы можем использовать union и структуры внутри операторов #define.Как они интерпретируются компилятором?
  2. Что означают «name ## _ L» и «name ## L».?, Особенно «##».
  3. Что такое «__ACCESS_20BIT_REG__ name»"?
  4. Что это за новый символ" @ ", я гуглил, чтобы узнать об этом символе, и я нигде не нахожу ничего, связанного с символом @, некоторые люди говорят, что это не стандарт С, верно ли это?, и что это значит?

Кто-то, пожалуйста, объясните мне это спокойствие кода, все зависит от этого фрагмента кода, и все прямо или косвенно использует этот #define.(

Ответы [ 3 ]

0 голосов
/ 06 февраля 2019

Я думаю, что лучший способ объяснить этот кусок кода - это попробовать пример: так, что получается из определения DEFA(name, address)?

Используя определение, например DEFA(myName, myAddress), препроцессор создает следующие строки кода:

__no_init union
{
  struct
  {
    volatile unsigned char  myName_L;
    volatile unsigned char  myName_H;
  };
  struct
  {
    volatile unsigned short myNameL;
    volatile unsigned short myNameH;
  };
  __ACCESS_20BIT_REG__ myName;
} @ myAddress;

Итак, теперь к вашим вопросам:

  1. Интерпретируется, как показано
  2. Это называется конкатенацией токенов, которая объединяет данный токен с переменной marco en.wikipedia.org / wiki / C_preprocessor # Token_concatenation
  3. ACCESS_20BIT_REG вероятно, это 20-битный тип данных, который определен где-то еще
0 голосов
/ 06 февраля 2019
  1. Я не знал, что мы можем использовать объединения и структуры внутри операторов #define.Как они интерпретируются компилятором?

Определить операторы - это просто макросы.Они НЕ интерпретируются компилятором, а препроцессором.Этот бит кода, который определен внутри макроса, просто вставляется копированием везде, где вы вызываете / используете этот макрос.Если он содержит допустимый код C / C ++, то он будет скомпилирован и на следующем шаге, как только препроцессор будет готов.

Что означают "name ## _ L" и "name ## L".?, Особенно "##".

Да, меня это удивило ##когда-то тоже.Это объединение токенов.По сути, вы можете генерировать «программно» имена переменных / функций, используя его.Так, например, у вас есть,

#include <stdio.h> 
#define concat(a, b) a##b 
int main(void) 
{ 
    int foobar = 1; 
    printf("%d", concat(foo, bar)); 
    return 0; 
} 

будет печатать 1, поскольку объединяет foo и bar вместе, чтобы сформировать foobar.

Что такое "__ACCESS_20BIT_REG__ name"?

__ACCESS_20BIT_REG__, по-видимому, определяемый реализацией макрос , определенный, вероятно, где-то еще в коде.Двойное подчеркивание __, за которым следует заглавная буква, зарезервировано для реализации (так что они могут использоваться, например, вашим производителем ОК).

Что это за новый символ "@", я гуглил, чтобы узнать об этом символе, и я нигде не нахожу ничего, связанного с символом @, некоторые люди говорят, что это не стандарт С, это правда? И чтоэто значит?

Этот тоже меня озадачил.Я не думаю, что это законно C.

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

На самом деле, что касается вашего пункта 4, то есть @ символ, я погуглил еще немного и нашел это stackoverflow вопрос .

0 голосов
/ 06 февраля 2019
  1. Вы можете поместить большинство вещей в макросы, в основном это просто замена текста (хотя и на уровне токена).Однако помещать определения типов и объявления переменных внутри макросов - это плохая практика, и ее следует избегать, если нет другой опции.

  2. Он вставляет токен в прошлое и создает новый токен препроцессора.В этом случае он создает имена переменных-членов.Если вы используете DEFA(foo,0), вы получите члены с именами foo_H и foo_L.

    Примечательно, что этот конкретный макрос, вероятно, был бы лучше, если бы поля были просто названы H и L. Почему кто-то хотел бывведите reg.foo_H вместо foo.H?Использование _L против L постфикса для различия между 8 и 16-битным доступом также не очень хорошая идея.

  3. Некоторый пользовательский тип, используемый тем же кодом.Почему у них есть объединение между чем-то, называемым «20-битными» и 32-битными структурами, я понятия не имею.

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

Также примечательно, что синтаксис объединения не является стандартным C. Вам необходимоНазовите союз.Анонимные структуры являются стандартными C начиная с C11, но я сомневаюсь, что это от современного компилятора.

В целом очень плохой код.Очень типичный вид мусорного кода, который вы можете найти в картах регистров микроконтроллеров, поставляемых поставщиками кремниевых инструментов.Не соответствует ни ISO C, ни MISRA-C.

...