проблема с внешней переменной - PullRequest
2 голосов
/ 24 мая 2010

У меня есть 2 файла cpp и файл заголовка, который я включил в оба файла cpp.Это так:

abc.h

extern uint32_t key;

a.cpp

#include "abc.h"
uint32_t key;
int main
{
.............
}

b.cpp

#include "abc.h"

int main
{
printf("Key: %.8x\n", key);
.............
}

Теперь, когда я компилируюa.cpp, ошибки нет.но когда я компилирую b.cpp, он выдает ошибку "неопределенная ссылка на ключ".Пожалуйста, помогите мне найти проблему в этом коде.

Ответы [ 6 ]

9 голосов
/ 24 мая 2010

Чтобы поделиться переменной, у вас обычно есть что-то вроде этого:

// A.h
extern int key;
void show();

//a.cpp
#include "a.h"

int main() { 
    key = 1;
    show();
};

// b.cpp
#include "a.h"
#include <iostream>

int key;

void show() { std::cout << "Key = " << key; }

Здесь есть пара моментов, которых здесь нет.Прежде всего, вы помещаете объявление extern в заголовок и включаете его в все файлы, которые используют переменную.Определите переменную (без extern) в одном и только одном файле.Только один файл должен содержать функцию с именем main.

Редактировать: чтобы построить это, вы компилируете каждый файл отдельно, но вы должны связать два файла вместе.Например, используя gcc, вы можете сделать что-то вроде:

gcc -c a.c
gcc -c b.c
gcc a.o b.o

Первый компилирует (но не связывает) ac Второй делает то же самое с bc. Третий фактически связывает их вместе и создает двоичноеможет выполняться (традиционно называется a.out, хотя, например, в Windows это обычно изменяется на a.exe).

3 голосов
/ 24 мая 2010

Проблема именно в том, что говорится в сообщении об ошибке.Abc.h объявляет переменную, но она не определяет ее.Строка в a.cpp определяет это.То есть a.cpp - это место, где появляется физическое хранилище переменной.В b.cpp такой строки нет, поэтому, когда вы попытаетесь скомпилировать эту программу, компоновщик останется без хранилища, определенного для этой переменной.

Если вы опустите в заголовке спецификатор "extern", тогдаb.cpp скомпилировался бы нормально, но a.cpp, вероятно, вывел бы ошибку о нескольких определениях.

Спецификатор "extern" играет большую роль, когда у вас есть несколько исходных файлов в одной программе.В этом случае, вероятно, все они будут включать abc.h, но без «extern» каждый скомпилированный объектный файл будет иметь свое собственное независимое определение той же переменной.Обычно компоновщик не знает, что с этим делать, и, вероятно, будет жаловаться, хотя я не думаю, что это необходимо.Исправление заключается в использовании «extern», поэтому каждый файл скомпилированного файла имеет только объявление .Затем вы выбираете один исходный файл для размещения определения. Вы, вероятно, поместите его в abc.cpp, поскольку объявление находится в abc.h.

2 голосов
/ 24 мая 2010

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

1 голос
/ 24 мая 2010

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

В вашем случае у вас есть определение в a.cpp, так что оно содержит все необходимое для сборки программы. b.cpp не имеет определения, поэтому ссылка не будет установлена.

Есть два решения. Либо скопируйте определение из a.cpp в b.cpp, либо переместите его в третий исходный файл и включите его в список источников при сборке обеих программ.

1 голос
/ 24 мая 2010

Я предполагаю, что вы получаете ошибку ссылки? Вы должны включить a.o при связывании b, хотя, если у вас действительно есть «main» в a и b, это не сработает. Вам нужно будет создать c.cpp, который объявляет ключ, и связать c.o с a.exe и b.exe.

0 голосов
/ 24 мая 2010

Для обеих a.cpp и b.cpp определены main() функции, и вам разрешено определять только одну main() для каждой программы.Итак, я предполагаю, что вы пытаетесь разделить файл заголовка между двумя программами.В этом случае добавьте строку к b.cpp для определения key и перекомпилируйте:

uint32_t key;

Это не обычный способ использования заголовочных файлов.Вместо этого вы пишете свои функции, чтобы принять key в качестве параметра.Делая это таким образом, вы настраиваете глобальную переменную, которая, как правило, хмурится.

extern почти всегда используется для установки глобальной переменной (в верхней части моей головы, я не могу думать ни о какихдругая причина использовать extern).Но если вы хотите использовать extern так, как это обычно используется - не вдаваясь в то, следует ли вообще его использовать - вы бы сделали следующее:

  • удалите функцию main() изодин из двух файлов, для целей этого ответа мы удалим его из b.cpp.
  • Используйте следующие две строки для компиляции и компоновки вашей программы (при условии gcc):

    gcc -c -o b.o b.cpp

    gcc a.cpp b.o

Опция -c для gcc (первая строка) говорит: « только компиляция, нессылка «.Это шаг связывания, который определяет, определены ли все переменные, и они не определяются при компиляции b.cpp, но они определяются при компиляции a.cpp (вторая строка).

...