LINUX.ORG.RU

Простой вопрос по СИ

 


0

2

Есть заголовочный файл example.h. В нём объявлена переменная.

struct idenf storage[256];
Данный файл подключен в example1.c, example2.c и example3.c. Если в файле example1.c изменить содержимое одного из элементов этого массива, при доступе к storage из файла example2.c будут ли видны эти изменения?

★★★

Все файлы примеров компилируются в один бинарник или по отдельности? Если в один, то у тебя только один поток выполнения. Если в разные, то не будут.

Lilly ()

если переменная объявлена как у вас - то это ошибка :-)

в хидере должно быть «extern struct ....» и в одном из C-шников уже сама переменная

MKuznetsov ★★★★★ ()

Если ты будешь собирать example1.c example2.c и example3.c в один бинарник, то у тебя будет ошибка линковки потому что в каждом объектном файле будет лежать переменная storage и случится конфликт имен.

Если ты хочешь иметь доступ из каждого файла, то ты должен объявить переменную в одном из с-файлов а в example.h написать extern struct idenf storage[256];

Tweaker ★★★★☆ ()

На кой хрен ты такое извращение делаешь?

anonymous ()

В нём объявлена переменная

Не как extern? Тогда того, кто эту хрень написал, надо посадить на кол без наркоза.

anonymous ()

Так попробуй сам, делов то.

$ cat example.h
#ifndef LOR
#define LOR
struct idenf {
	int val;
};
struct idenf storage[256];
#endif

$ cat example.c
#include <stdio.h>
#include "example.h"

extern void f1();
extern void f2();
extern void f3();

void p()
{
	int i = 0;
	for (i = 0; i < 4; ++i)
		printf("[%d] %d\n", i, storage[i].val);
}

int main()
{
	p();
	f1();
	f2();
	f3();
	p();
}
$ cat example1.c
#include "example.h"
void f1()
{
	storage[1].val = 1;
}
$ cat example2.c
#include "example.h"
void f2()
{
	storage[2].val = 2;
}
$ cat example3.c
#include "example.h"
void f3()
{
	storage[3].val = 3;
}
$ gcc -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/c++/4.2.1
Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.0.0
Thread model: posix
$ gcc example1.c example2.c example3.c example.c -o example -Wall
$ ./example 
[0] 0
[1] 0
[2] 0
[3] 0
[0] 0
[1] 1
[2] 2
[3] 3
$ 
bk_ ★★ ()
Ответ на: комментарий от bk_

А на счет extern товарищи выше абсолютно правы.

bk_ ★★ ()
Ответ на: комментарий от Tweaker

$ cat tst.c

#include <stdio.h>
int x;
int g();
int f(){
    x++;
    return x;
}
int main(){
    printf("%d\n", f());
    printf("%d\n", g());
    printf("%d\n", f());
    printf("%d\n", g());
    printf("%d\n", f());
}

$ cat a.c

int x;
int g(){
    x++;
    return x;
}

$ gcc a.c tst.c
$ ./a.out 
1
2
3
4
5

Поблажки линкера?

Waterlaz ★★★★★ ()
Последнее исправление: Waterlaz (всего исправлений: 2)
Ответ на: комментарий от MKuznetsov

ORLY? А какого тогда программа компилируется и в .с файлах данная переменная доступна?

LIKAN ★★★ ()
Ответ на: комментарий от Tweaker

Вот-вот, у меня вот и было такое подозрение, что должен быть конфликт имен. Но тем не менее его почему-то не происходит.

LIKAN ★★★ ()
Ответ на: комментарий от LIKAN

Не должно быть конфликта имён: это объявление внешней переменной. Все объявления с одним именем из разных объектных файлов линковщик склеит в одно.

Вот если бы ты написал int x = 1;, это бы не прокатило. Поскольку тут не только объявление, но и инициализация. Внешняя переменная может быть инициализирована только в одном из файлов (или ни в одном — тогда по умолчанию инициализируется нулями).

Deleted ()
Ответ на: комментарий от MKuznetsov

в хидере должно быть «extern struct ....» и в одном из C-шников уже сама переменная

Изучите матчасть, extern в этом объявлении компилятор по умолчанию подставляяет.

Слово extern важно не столько для компилятора, сколько для программиста, которому этот код читать.

Deleted ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.