Экспериментируя с глобальными переменными и функциями в C - PullRequest
2 голосов
/ 03 июля 2011

Я пытаюсь понять, как глобальные переменные и функции работают в C. Моя программа компилируется и прекрасно работает с gcc, но не компилируется с g++. У меня есть следующие файлы:

globals.h:

int i;
void fun();

globals.c:

#include "stdlib.h"
#include "stdio.h"

void fun()
{
  printf("global function\n");
}

main.c:

#include "stdlib.h"
#include "stdio.h"
#include "globals.h"

void myfun();

int main()
{

  i=1;

  myfun();

  return 0;
}

И, наконец, myfun.c :

#include "stdlib.h"
#include "stdio.h"
#include "globals.h"

void myfun()
{
  fun();
}

Я получаю следующую ошибку при компиляции с g ++:

/tmp/ccoZxBg9.o:(.bss+0x0): multiple definition of `i'
/tmp/ccz8cPTA.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status

Есть идеи, почему? Я бы предпочел скомпилировать с g ++.

Ответы [ 4 ]

6 голосов
/ 03 июля 2011

Каждый файл, из которого вы включаете globals.h, будет определять "int i".

Вместо этого введите "extern int i;"в заголовочный файл и затем поместите фактическое определение «int i = 1;»в globals.c.

Было бы разумно поместить ограждение для заголовков вокруг globals.h.

Edit : В ответ на ваш вопрос это потому, что #include работает вродекак вырезать и вставить.Он вставляет содержимое включенного файла в файл c, из которого вы вызываете include.Поскольку вы включаете «globals.h» из main.c и myfun.c, вы определяете int i = 1 в обоих файлах.Это значение, будучи глобальным, заносится в таблицу связанных значений.Если у вас есть одно и то же имя переменной дважды, то компоновщик не сможет сказать, какая ему нужна, и вы получите сообщение об ошибке, которую видите.Вместо этого, добавляя extern в начало заголовочного файла, вы говорите каждому файлу, что «int i» определено где-то еще.Очевидно, вам нужно определить его где-то еще (и ТОЛЬКО в одном месте), поэтому определение его в globals.c имеет смысл.

Надеюсь, это поможет:)

1 голос
/ 03 июля 2011

Несколько вещей здесь не так; настоятельно рекомендуется несколько других вещей:

globals.h:


#ifndef GLOBALS_H
#define GLOBALS_H

extern int my_global;

#ifdef __cplusplus
extern "C" {
#endif 
void fun();
#ifdef __cplusplus
}
#endif 

#endif
/* GLOBALS_H */

globals.c:


#include <stdlib.h>
#include <stdio.h>
#include "globals.h"

int my_global;

void fun()
{
  printf("global function: %d\n", my_global);
}

main.c:


#include <stdlib.h>
#include <stdio.h>
#include "globals.h"

void myfun();

int main()
{

  my_global=1;

  myfun();

  return 0;
}

void myfun()
{
  fun();
}
  1. Вы должны объявить "extern int myvar" в своем заголовке и фактически разместить "int myvar" в одном и только одном файле .c.

  2. Вы должны включать «globals.h» в каждый файл, который использует «myvar», включая файл, в котором он размещен.

  3. Особенно, если вы планируете смешивать модули C и C ++, вы должны использовать 'extern "C" для различения не-C ++ функций.

  4. Системные заголовки должны быть "#include "; ваши собственные заголовки должны вместо этого использовать кавычки (#include "myheader.h").

  5. Короткие имена переменных, такие как «i», могут быть вполне допустимыми для строго локальной переменной (например, индекс цикла), но вы всегда должны использовать более длинные описательные имена всякий раз, когда невозможно избежать использования глобальной переменной.

  6. Я добавил «printf» для my_global.

Надеюсь, это поможет!

1 голос
/ 03 июля 2011

Я бы добавил в ваш глобальный файл включенную охрану

#ifndef GLOBALS_H
#define GLOBALS_H

int i;
void fun();

#endif

Редактировать: изменить глобальные переменные так, чтобы они были такими (используя extern, как описано в другом ответе)

globals.h

extern  int i;
extern  void fun();

globals.c

#include "stdlib.h"
#include "stdio.h"
int i;
void fun()
{
  printf("global function\n");
}

Я скомпилировал это с

g++ globals.c main.c myfun.c

и все прошло нормально

0 голосов
/ 23 марта 2014

У меня была эта проблема при переносе старого кода C на C ++. Проблема была в том, что это был проект, который был подключен к базе данных, и я хотел портировать базу данных на c ++, но не на все остальное. База данных вытягивала некоторые зависимости C, которые не могли быть перенесены, поэтому мне нужен был код C, который перекрывал и базу данных, и другой проект для компиляции в g ++, а также в gcc ...

Решением этой проблемы является определение всех переменных как extern в файле .h . затем, когда вы компилируете в gcc или g ++, он сообщит о символах, отсутствующих в файлах .c. Поэтому отредактируйте файлы .c в сообщениях об ошибках и вставьте объявление в все файлы .c, которым нужны переменные. Примечание: вам, возможно, придется объявить это в нескольких файлах .c, что меня бросило и почему я застрял на этой проблеме целую вечность.

В любом случае это решило мою проблему, и код теперь аккуратно компилируется как в gcc, так и в g ++.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...