Что такое extern volatile указатель
что такое extern volatile указатель.
extern volatile uint32 *ptr;
здесь, каким будет поведение *ptr? Что это на самом деле означает?
и, когда его следует использовать?
Я попытался google об этом, но не получил удовлетворительного ответа, нет много информации об этой комбинации.
4 ответов
и extern и летучие ключевые слова можно рассматривать независимо. Роль каждого из этих ключевых слов не взаимодействует с другим, и поэтому объяснение каждого из них может быть детализировано независимо, как показано ниже.
extern сообщает компилятору, что фактическое определение ptr в другом модуле (другой .c
). В принципе, нет особых изменений в том, как компилятор обрабатывает ptr - наличие extern просто сообщает компилятору, что ему не нужно резервировать место в памяти для ptr как это делается в другом месте в другом .c
, и его фактическое местоположение памяти будет задано линкер позже.
extern uint32 *ptr;
если вы опустите extern компилятор не будет жаловаться. Однако позже линкер, когда он пытается связать все объектные модули, чтобы построить окончательная исполняемая программа, выдаст сообщение об ошибке"ptr определяется дважды "(так как он уже определен в другом .c
).
uint32 *ptr;
летучие сообщает компилятору, что место в памяти, где ptr resides может быть изменен / изменен каким-либо внешним событием, и он (компилятор) не должен полагаться на некоторые оптимизации эффективности, например, учитывая, что значение ptr не изменится во время области a несколько последовательных строк C. Такое событие может быть асинхронным прерыванием, которое происходит, когда CPU выполняет вышеупомянутую область и изменяет ptr значение.
как правило (с виртуальным кодом сборки оптимизированного C в комментариях), REGx являются регистрами CPU, и нас не очень интересует переменная y...
int x = 10;
int func() {
int y; // REG4
printf("%d\n", x); // Set REG3 = memory(x) and display x
x += 2; // Add 2 to REG3
y = x * x; // REG4 = REG3 * REG3
printf("%d %d\n", x, y); // Do printf(..., REG3, REG4)
x += 5; // REG3 = REG3 + 5
// memory(x) = REG3 (save register to memory)
return y; // return REG4
}
должны отображаться 10, 12, 144
. Ради эффективности (доступ к памяти дороже, чем доступ к регистру) скажем, компилятор хранит значение x во внутреннем регистре процессора (REG3) и использует его в func благополучно до конца, где он хранит новое значение x (это глобальный var) to x место в памяти. x 17 в конце.
но представьте, что программа сложнее, чем это, и имеет прерывание часов каждую минуту, которая вычитает 10 до x. Что произойдет, если перерыв...
void inter_call_by_timer_every_minute() {
x -= 10;
}
... происходит в func скажи сразу после printf("%d\n", x);
линии? func и x в REG3 (10) добавьте 2 (12) и, наконец, добавьте 5 (17) и сохраните результат REG3 в x ячейки памяти (17). Это неправильно, так как эффект прерывания(-10) был скрыт оптимизацией компилятора, поскольку он сохраняет значение из REG3 в память (x) в конце, игнорируя вычесть сделано перерыв. Правильный результат:x первоначально 10, прерывание вычитает 10 к нему (0) после первого printf
на func, затем добавляется 2, затем 5. Результат 7.
добавлять летучие
volatile int x = 10;
компилятор будет избегать x оптимизация в func
int func() {
int y; // REG4
printf("%d\n", x); // display memory(x)
x += 2; // memory(x) += 2
y = x * x; // REG4 = memory(x) * memory(x)
printf("%d %d\n", x, y); // Do printf(..., memory(x), REG4)
x += 5; // memory(x) += 5
return y; // return REG4
}
и прочитайте значение x по памяти все время. Результат, имеющий прерывание от inter_call_by_timer_every_minute после первого printf, это x == 7.
Я бы объяснил, как я знаю через ключевые слова. extern
означает, что переменная определена для использования где-то вне области определения. Например, он может быть определен в файле заголовка и использоваться.файл c.
volatile
означает, что модификация этой переменной должна быть согласована с внешним миром. Это означает, что все обновления должны быть зафиксированы в основной памяти, чтобы их могли видеть другие потоки, имеющие одинаковое пространство выполнения.
extern
ключевое слово используется для объявления глобальной переменной, которая определена где-то еще (это означает, что она определена в каком-то другом ).
например рассмотрим в проекте два .c
файлы a.c
и b.c
не существует. В этом случае глобальная переменная определяется в a.c
, и что переменная может быть доступна во всех функциях, которые определены в этом файле. Если мы хотим получить доступ к той же глобальной переменной во втором файле b.c
, то переменная должна быть заявлена как extern
на b.c
ниже
int flag = 0;
int main()
{
.......
func1();
printf("\nflag value is %d\n", flag).
.......
}
ниже
extern int flag;
void func1();
{
.....
flag = 10;
.....
}
volatile
ключевое слово используется для информирования компилятора, чтобы избежать какой-либо оптимизации при генерации исполняемых инструкций.
int flag = 0;
int main()
{
while(flag == 0);
printf("\nflag value is %d\n", flag);
return 0;
}
рассмотрим вышеуказанную программу, весь компилятор оптимизирует while(flag == 0);
as while(1);
. Потому что в коде нет, где flag
значение обновляется до этого while
петли. Поэтому, если это значение переменной обновляется каким-то другим оборудованием, оно никогда не будет отражено в выполнении программы. Поэтому, если мы объявим эту переменную как volatile
как показано ниже, компилятор не будет выполнять никакой оптимизации для этой переменной, и поведение этой программы будет соответствовать назначению.
volatile int flag = 0;
но если нет никакого способа для значения переменной программы обновляется другим оборудованием, то нет необходимости объявлять эту переменную как volatile
. Потому что valatile переменные, CPU необходимо выполнить операцию ввода-вывода для каждой инструкции, которая обращается к этой переменной. Это влияние на производительность необходимо учитывать для переменной, которая никогда не будет обновляться другими аппаратными средствами.
Extern означает, что он определен в другом месте-возможно, в файле заголовка. Volatile-это информация для компилятора, которую он не должен пытаться оптимизировать.