Язык C: как интерпретировать этот #define? - PullRequest
2 голосов
/ 13 февраля 2012

Я нашел этот фрагмент на сайте:

#define DISPLAY_CR  (*(volatile unsigned int *) 0x4000000) 
DISPLAY_CR = somevalue;

, который должен описывать DISPLAY_CR как переменный указатель типа unsigned int на адрес 0x4000000

Я не понимаю, почему:

  • двойное круглое скобление?
  • две звезды используют (почему две звезды, а не только одна?)

Ответы [ 7 ]

6 голосов
/ 13 февраля 2012

Дополнительные скобки являются стандартной практикой в ​​макросах. Макросы развертываются в режиме копирования и вставки, поэтому без скобок приоритет может быть изменен в зависимости от контекста.

Игнорируя лишние скобки, ваш код расширяется до:

*(volatile unsigned int *) 0x4000000 = somevalue;

, что эквивалентно:

volatile unsigned int *p = 0x4000000; // Treat this as the address of a volatile unsigned int
*p = somevalue; // Write to that address

что, надеюсь, должно быть яснее.

2 голосов
/ 13 февраля 2012

Скобки вокруг всего выражения важны для всех макросов и критически важны для макросов, подобных перечисленному.

Если кто-то должен был написать, скажите:

int foo = DISPLAY_CR++;

и тамне было бы скобок, заключающих макрос, которые бы анализировались как:

int foo = *(volatile unsigned int *)(0x4000000++);

, что имеет совершенно другое значение.

2 голосов
/ 13 февраля 2012

У вас есть

  • 0x4000000 - адрес 0x4000000
  • (volatile unsigned int *) 0x4000000 - приведение к летучему указателю
  • * (volatile unsigned int *) 0x4000000 - разыменовать указатель, чтобы сделать lvalue
  • (*(volatile unsigned int *) 0x4000000) - заключите в дополнительный набор скобок, чтобы DISPLAY_CR был фактически единым токеном - вы не столкнетесь с проблемами приоритета операторов и т. Д. Вокруг него
2 голосов
/ 13 февраля 2012

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

1 голос
/ 13 февраля 2012

Этот макрос не описывает DISPLAY_CR как переменный указатель типа unsigned int на адрес 0x4000000. Он описывает DISPLAY_CR как целое число без знака значение , расположенное в 0x4000000, скорее всего, аппаратно-зависимом регистре.

Причина, по которой вам нужно volatile, состоит в том, чтобы запретить компилятору "оптимизировать" множественные записи в регистр оборудования. Например, если вам нужно что-то сигнализировать аппаратному обеспечению, установив значение в 1 и затем очистив его, вы можете написать

DISPLAY_CR = 1;
DISPLAY_CR = 0;

Без volatile компилятор может отбросить первое присваивание как незначительное; volatile препятствует этому.

0 голосов
/ 13 февраля 2012

ОК, давайте разберемся с этим.

Очевидно, 0x4000000 - это число, которое мы хотим использовать для указания определенного адреса памяти (надеюсь, там есть что-то важное).

Теперь (volatile unsigned int *) - это cast , что означает, что он сообщает компилятору, что необходимо принудительно указать тип аргумента для указанного типа (который является указателем на целое число без знака, volatile).

Наконец, * является оператором разыменования. Это означает, что мы хотим получить доступ к значению, хранящемуся в этом адресе.

Дополнительные круглые скобки - просто хороший стиль при использовании макросов - программисты на C особенно осторожны с ними, поскольку правила приоритета операторов немного сбивают с толку.

0 голосов
/ 13 февраля 2012

Звезда внутри означает, что тип является указателем на unsigned int.Внешняя звезда разыменовывает указатель на блок памяти, на который она указывает.

...