Невозможно получить доступ к переменным (объявленным в основном) в процедуре прерывания IAR / STM32 [duplicate]

Вы можете использовать понимание списка:

>>> s = 'hi'
>>> [ord(c) for c in s]
[104, 105]
839
задан Lundin 22 May 2017 в 07:01
поделиться

13 ответов

Правильная интерпретация extern заключается в том, что вы сообщаете что-то компилятору. Вы сообщаете компилятору, что, несмотря на то, что он не присутствует прямо сейчас, объявленная переменная каким-то образом будет найдена компоновщиком (как правило, в другом объекте (файле)). Компилятор тогда будет счастливым парнем, чтобы найти все и собрать его вместе, были ли у вас некоторые объявления extern или нет.

11
ответ дан Alex Lockwood 18 August 2018 в 13:03
поделиться

ключевое слово extern используется с переменной для ее идентификации как глобальной переменной.

Оно также означает, что вы можете использовать переменную, объявленную с использованием ключевого слова extern, в любом файл, хотя он объявлен / определен в другом файле.

7
ответ дан Anup 18 August 2018 в 13:03
поделиться

Extern - это ключевое слово, которое вы используете, чтобы объявить, что сама переменная находится в другой единицы перевода.

Таким образом, вы можете решить использовать переменную в блоке трансляции, а затем получить доступ к ней из другой, затем в второй, который вы объявляете как extern, и символ будет разрешен компоновщиком.

Если вы не объявите его как extern, вы получите две переменные, которые будут одинаковыми, но не связаны вообще, и ошибка нескольких определений переменной.

35
ответ дан Arkaitz Jimenez 18 August 2018 в 13:03
поделиться

extern сообщает компилятору доверять вам, что память для этой переменной объявлена ​​в другом месте, поэтому она не пытается выделить / проверить память.

Поэтому вы можете скомпилировать файл, который ссылается на extern, но вы не можете связать, если эта память не была объявлена ​​где-то.

Полезно для глобальных переменных и библиотек, но опасно потому что компоновщик не устанавливает проверку.

17
ответ дан BenB 18 August 2018 в 13:03
поделиться

Мне нравится думать о переменной extern в качестве обещания, которое вы делаете в компиляторе.

Когда встречается с extern, компилятор может узнать только его тип, а не там, где он «живет», поэтому он не может разрешить ссылку.

Вы говорите: «Поверьте мне. В момент ссылки эта ссылка будет разрешаемой».

23
ответ дан Buggieboy 18 August 2018 в 13:03
поделиться
  • 1
    В более общем плане, объявление является обещанием, что имя будет разрешено точно одному определению во время связи. Extern объявляет переменную без определения. – Lie Ryan 30 November 2010 в 03:16

Реализация GCC ELF Linux

main.c:

#include <stdio.h>

int not_extern_int = 1;
extern int extern_int;

void main() {
    printf("%d\n", not_extern_int);
    printf("%d\n", extern_int);
}

Скомпилировать и декомпилировать:

gcc -c main.c
readelf -s main.o

Выход содержит:

Num:    Value          Size Type    Bind   Vis      Ndx Name
 9: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 not_extern_int
12: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND extern_int

В главе System V ABI Update ELF spec главу «Таблица символов» объясняется:

SHN_UNDEF Этот индекс таблицы разделов означает, что символ не определен. Когда редактор ссылок объединяет этот объектный файл с другим, который определяет указанный символ, ссылки этого файла на символ будут связаны с фактическим определением.

, который в основном является поведением, которое дает стандарт C to extern.

С этого момента задача компоновщика заключается в создании окончательной программы, но информация extern уже извлечена из исходного кода в объектный файл.

Проверено на GCC 4.8.

5
ответ дан Ciro Santilli 新疆改造中心 六四事件 法轮功 18 August 2018 в 13:03
поделиться
  • 1
    Это не мой голос, поэтому я не знаю. Однако я выскажу мнение. Хотя просмотр результатов работы readelf или nm может быть полезным, вы не объяснили основы использования extern и не выполнили первую программу с фактическим определением. Ваш код даже не использует notExtern. Проблема с номенклатурой тоже: хотя notExtern здесь определен, а не объявлен с помощью extern, это внешняя переменная, к которой могут обращаться другие исходные файлы, если эти единицы перевода содержали подходящее объявление (для чего понадобилось бы extern int notExtern; !). – Jonathan Leffler 30 August 2015 в 14:57
  • 2
    @JonathanLeffler благодарит за отзыв! Стандартные рекомендации по поведению и использованию уже были сделаны в других ответах, поэтому я решил показать реализацию немного, так как это действительно помогло мне понять, что происходит. Не использовать notExtern было уродливо, исправлено. О номенклатуре, дайте мне знать, если у вас есть лучшее имя. Конечно, это не было бы хорошим именем для реальной программы, но я думаю, что здесь хорошо подходит дидактическая роль. – Ciro Santilli 新疆改造中心 六四事件 法轮功 2 September 2015 в 14:52
  • 3
    Что касается имен, как насчет global_def для переменной, указанной здесь, и extern_ref для переменной, определенной в каком-либо другом модуле? Имеют ли они соответственно четкую симметрию? Вы все еще получаете int extern_ref = 57; или что-то подобное в файле, где он определен, поэтому имя не совсем идеально, но в контексте одного исходного файла это разумный выбор. Мне кажется, что extern int global_def; в заголовке не так много проблемы. Конечно, конечно. – Jonathan Leffler 2 September 2015 в 14:56

Добавление extern превращает определение переменной в объявление переменной . См. этот поток относительно того, в чем разница между объявлением и определением.

15
ответ дан Community 18 August 2018 в 13:03
поделиться

В C переменная внутри файла say example.c предоставляется локальная область. Компилятор ожидает, что переменная будет иметь свое определение внутри одного и того же файла example.c, и когда он не найдет то же самое, это вызовет ошибку. Функция, с другой стороны, имеет глобальную область по умолчанию. Таким образом, вам не нужно явно упоминать компилятор «посмотрите чувак ... вы можете найти определение этой функции здесь». Для функции, содержащей файл, содержащий его объявление, достаточно. (Файл, который вы на самом деле называете заголовочным файлом). Например, рассмотрим следующие 2 файла: example.c

#include<stdio.h>
extern int a;
main(){
       printf("The value of a is <%d>\n",a);
}

example1.c

int a = 5;

Теперь, когда вы скомпилируете два файла вместе, используйте следующие команды:

шаг 1) cc -o ex example.c example1.c, этап 2) ./ ex

Вы получаете следующий вывод: значение a равно & lt; 5 & gt;

8
ответ дан jogabonito 18 August 2018 в 13:03
поделиться

extern просто означает, что переменная определена в другом месте (например, в другом файле).

1489
ответ дан Jonathan Leffler 18 August 2018 в 13:03
поделиться
  • 1
    @litb: см. Приложение J.5.11 для общего определения - это общее расширение. – Jonathan Leffler 16 September 2009 в 16:19
  • 2
    @litb: и я согласен, что этого следует избегать - вот почему он находится в разделе «Не так хорошо определить глобальные переменные». – Jonathan Leffler 16 September 2009 в 16:20
  • 3
    На самом деле это общее расширение, но это неопределенное поведение для программы, чтобы полагаться на нее. Я просто не понял, говоришь ли ты, что это разрешено собственными правилами С. Теперь я вижу, что вы говорите, что это просто общее расширение и избежать этого, если вам нужен ваш код для переносимости. Поэтому я могу поддержать вас без всяких сомнений. Действительно отличный ответ ИМХО :) – Johannes Schaub - litb 16 September 2009 в 16:30
  • 4
    @Zak: Нет. Условным кодом в file3a.h является #ifdef DEFINE_VARIABLES / #define EXTERN / #else / #define EXTERN extern / #endif, удаление комментариев и использование косой черты для обозначения концов строк. Если указано DEFINE_VARIABLES, то переменные не должны иметь префикс extern, который будет отмечать их как декларации вместо определений. Это, в свою очередь, означает, что компилятор будет выделять пространство для переменных, а не просто записывать их существование. – Jonathan Leffler 16 January 2013 в 04:14
  • 5
    Если вы остановитесь наверху, это упростит простые вещи. По мере того, как вы читаете дальше, это касается большего количества нюансов, сложностей и деталей. Я только что добавил две «ранние остановки» для менее опытных программистов на С - или программистов С, которые уже знают предмет. Нет необходимости читать все это, если вы уже знаете ответ (но дайте мне знать, если вы найдете техническую ошибку). – Jonathan Leffler 5 August 2014 в 04:28
  • 6
    Обратите внимание, что объявление extern должно быть в заголовке, а не в first.c, так что если тип изменяется, объявление также изменится. Кроме того, заголовок, объявляющий переменную, должен быть включен second.c, чтобы убедиться, что определение соответствует декларации. Объявление в заголовке - это клей, который держит его вместе; он позволяет скомпилировать файлы отдельно, но обеспечивает согласованное представление типа глобальной переменной. – Jonathan Leffler 2 September 2015 в 15:09

Переменная extern - это объявление (благодаря sbi для коррекции) переменной, которая определена в другой единицы перевода. Это означает, что хранилище для переменной выделено в другом файле.

Скажем, у вас есть два файла .c test1.c и test2.c. Если вы определяете глобальную переменную int test1_var; в test1.c и хотите получить доступ к этой переменной в test2.c, вы должны использовать extern int test1_var; в test2.c.

Полный образец:

$ cat test1.c 
int test1_var = 5;
$ cat test2.c
#include <stdio.h>

extern int test1_var;

int main(void) {
    printf("test1_var = %d\n", test1_var);
    return 0;
}
$ gcc test1.c test2.c -o test
$ ./test
test1_var = 5
108
ответ дан jww 18 August 2018 в 13:03
поделиться
  • 1
    Нет «псевдо-определений». Это декларация. – sbi 16 September 2009 в 15:18
  • 2
    В приведенном выше примере, если я изменяю extern int test1_var; на int test1_var;, компоновщик (gcc 5.4.0) все еще проходит. Итак, действительно ли extern нужен в этом случае? – radiohead 24 March 2018 в 04:15
  • 3
    @radiohead: в моем ответе вы найдете информацию о том, что удаление extern является общим расширением, которое часто работает, и, в частности, работает с GCC (но GCC далеко не единственный компилятор, который поддерживает это, он распространен на Unix-системах). Вы можете найти «J.5.11». или раздел «Не очень хороший способ». в моем ответе (я знаю - это is long), и текст рядом с ним объясняет (или пытается это сделать). – Jonathan Leffler 16 June 2018 в 19:44
1499
ответ дан Jonathan Leffler 7 September 2018 в 00:09
поделиться
1522
ответ дан Jonathan Leffler 30 October 2018 в 04:33
поделиться
0
ответ дан user50619 30 October 2018 в 04:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: