2016-12-28 7 views
2

У меня возникла проблема, с которой я не могу решить проблему, в которой, как утверждается, глобальная переменная исправлена ​​на единственной строке, где она объявлена. У меня есть следующий код:Общая глобальная переменная Typedef'd в C Redeclared

test_regs.h:

#define TEST_REGS_BASE_ADDRESS  0xA0080000 

typedef struct { 
    union { 
     unsigned int data; 
     struct { 
      unsigned int RESERVED  : 16; 
      unsigned int CHAR1  : 8; 
      unsigned int CHAR0  : 8; 
     }; 
    }; 
} TEST_REG_STRUCT; 

typedef struct { 
    TEST_REG_STRUCT      TEST_REG; 
} *TEST_REGS; 

tasks.h:

#ifndef TASKS_H 
#include "test_regs.h" 

volatile TEST_REGS    TST; // This line throws an error 
volatile int     ok_global; 

void func(); 

#define TASKS_H 
#endif 

tasks.c:

#include "tasks.h" 

void func() { 
    TST->TEST_REG.CHAR1 = 0x52; 
    TST->TEST_REG.CHAR0 = 0x51; 
    ok_global++; 
} 

main.c:

#include "tasks.h" 

main() { 
    TST = (TEST_REGS) TEST_REGS_BASE_ADDRESS; 
    ok_global = 0; 
    func(); 
} 

я пытаюсь скомпилировать код выше с помощью следующей команды (используя минимальную версию GCC, разработанную для процессора Leon3):

sparc-elf-gcc -msoft-float -c -g -O2 -o test.o tasks.c main.c

Это компилировать попытку производит следующие ошибки:

tasks.h:4: error: conflicting types for 'TST'

tasks.h:4: error: previous declaration of 'TST' was here

Следует отметить, что глобальная переменная, ok_global не поз любая проблема; только переменная, тип, объявленный в test_regs.h, TST, выдает указанную выше ошибку. Это означает, что ошибка не может быть вызвана тем, что заголовок tasks.h получил несколько раз. Кто-нибудь знает, почему мой код, как написано, является незаконным?

Я хотел бы отметить, что если я избавлюсь от всех заголовков, за исключением test_regs.h, и сделайте заявление в одном файле C, проблема исчезнет. Кроме того, я действительно должен иметь заголовок test_regs.h, отделенный от заголовка tasks.h, test_regs.h является машинным сгенерированным, а tasks.h - нет и будет меняться в зависимости от использования.


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

tasks.h:

#ifndef TASKS_H 
#define TASKS_H 
#define TEST_REGS_BASE_ADDRESS  0xA0080000 

typedef struct { 
    union { 
     unsigned int data; 
     struct { 
      unsigned int RESERVED  : 16; 
      unsigned int CHAR1  : 8; 
      unsigned int CHAR0  : 8; 
     }; 
    }; 
} TEST_REG_STRUCT; 

typedef struct { 
    TEST_REG_STRUCT      TEST_REG; 
} *TEST_REGS; 

extern volatile TEST_REGS    TST; 
volatile int     ok_global; 

void func(); 

#endif 

tasks.c:

#include "tasks.h" 

volatile TEST_REGS TST; 

void func() { 
    TST->TEST_REG.CHAR1 = 0x52; 
    TST->TEST_REG.CHAR0 = 0x51; 
    ok_global++; 
} 

главный.C: команда

#include "tasks.h" 

main() { 
    TST = (TEST_REGS) TEST_REGS_BASE_ADDRESS; 
    ok_global = 0; 
    func(); 
} 

Compile:

sparc-elf-gcc -msoft-float -c -g -O2 -o test.o tasks.c main.c

Результат:

tasks.h:20: error: conflicting types for 'TST'

tasks.c:3: error: previous declaration of 'TST' was here

Существует что-то конкретное для TST что Зав глобальный обмен; это не просто общий вопрос «как делиться глобальными переменными».

+0

Переместите свой '#define TASKS_H' в начало файла, сразу после' #ifndef TASKS_H'. – e0k

+1

Не указывайте указатели 'typedef', это ужасная идея. Кроме, возможно, если они 100% непрозрачные типы. –

+1

e0k, спасибо за предложение, но это не решило проблему. Кроме того, я не думаю, что 'test_regs.h' может быть получен многократно, как есть, как может показаться в вашем предположении, поскольку такая же ошибка повторного выделения не возникает для' ok_global'. – user3570982

ответ

3

Переменные TST и ok_global: определены в tasks.h. Поскольку оба main.c и tasks.c включают этот заголовок, эти переменные определяются в обоих модулях. Когда эти модули затем связаны друг с другом, вы получаете ошибку для нескольких определений.

Глобальные переменные должны быть определены в одном файле .c. Любой файл .c, который должен ссылаться на него, должен содержать заголовочный файл, который содержит объявление этого глобального. В декларации говорится, что «эта переменная существует где-то», но не говорит точно где именно.

В tasks.h, вы объявляете переменные, как это:

extern volatile TEST_REGS    TST; 
extern volatile int     ok_global; 
void func(); 

Затем вы определяете их в tasks.c:

#include "tasks.h" 

volatile TEST_REGS    TST; 
volatile int     ok_global; 

void func() { 
    TST->TEST_REG.CHAR1 = 0x52; 
    TST->TEST_REG.CHAR0 = 0x51; 
    ok_global++; 
} 

Обратите внимание, что вы уже делаете это с func функция. Разница в том, что объявления переменных требуют ключевое слово extern, а объявления функций - нет.

+0

Но вы * можете * объявить функции 'extern', также, если хотите эту согласованность. Просто бывает излишним сделать это для них. –

+0

С уважением, это не то, что происходит. Это игнорирует макрокоманды, обернутые вокруг заголовочного файла 'tasks.h', чтобы исключить несколько деклараций, и игнорирует тот факт, что' ok_global' компилируется без ошибок. Эта проблема специфична для 'TST'. Кроме того, когда я объявляю 'TST' в' tasks.h' с 'extern', а затем объявляю его без' extern' в 'tasks.c', я все равно получаю ошибку« предыдущее объявление »; он просто указывает, что предыдущее объявление было в 'tasks.c' вместо' tasks.h'. – user3570982

+0

@ user3570982 Защитники макросов защищают от заданного заголовка, который включается более одного раза в данный исходный модуль, но он не ** защищает от нескольких исходных модулей, включая этот заголовок, и этот заголовок содержит такое определение, как у вас. Что касается 'ok_global', возможно, что компоновщик может только поймать первый экземпляр дублирующей переменной. Попробуйте указанные выше изменения и посмотрите, как это работает. – dbush