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

Наскоро започнах да осъзнавам, че използването на ключовата дума "extern" е силно насърчавано. Така започнах да се чудя дали има нещо нередно с текущия (без външен) начин, по който използвам заглавни файлове:

main.c:

#include "main.h"
#include "function.h"

int main(void){
    globalvariable = 0;

    testfunction();
    return 0;
}

main.h:

#ifndef MAIN_H_
#define MAIN_H_

int globalvariable;

#endif /* MAIN_H_ */

функция.c:

#include "main.h"
#include "function.h"

void testfunction(){
    globalvariable++;
    return;
}

функция.h:

#ifndef FUNCTION_H_
#define FUNCTION_H_

void testfunction(void);

#endif /* FUNCTION_H_ */

Така всеки нов изходен файл, който се нуждае от достъп до globalvariable, просто трябва да включва main.h.

Един очевиден недостатък на този метод са масивите: не можете да използвате форматиране {element0, element1, ...}, за да присвоите стойности на масив, след като той е бил деклариран.

Между другото, когато дам на globalvariable първоначална стойност нула, дефинирам ли я в този момент? Или паметта е разпределена по-рано?

Освен това има ли официален термин за метода, който използвам?


person SharpHawk    schedule 09.04.2012    source източник
comment
Ключовата дума extern не се насърчава много; трябва да го използвате само когато е абсолютно необходимо (което се надяваме никога).   -  person Oliver Charlesworth    schedule 10.04.2012
comment
stackoverflow.com/questions/1433204/   -  person cnicutar    schedule 10.04.2012
comment
Глобалните променливи са лоши.   -  person Fred Larson    schedule 10.04.2012
comment
интересно Усещането, което бях придобил от предишните нишки тук, беше, че extern е де факто начинът да се правят нещата.   -  person SharpHawk    schedule 10.04.2012
comment
Е, цитат от най-горния cnicutar, свързан към (който бих прочел, преди да публикувам въпроса си), гласи: Въпреки че има други начини да го направите, чистият, надежден начин за деклариране и дефиниране на глобални променливи е да използвате заглавен файл file3 .h да съдържа външна декларация на променливата. Оли, искаш да кажеш, че има по-добър начин за деклариране и дефиниране на глобални променливи?   -  person SharpHawk    schedule 10.04.2012
comment
@SharpHawk: Не (няма). Намеквам, че трябва да избягвате глобални променливи, споделени между множество единици за превод...   -  person Oliver Charlesworth    schedule 10.04.2012
comment
ААА добре. Липсата на класове в C беше основната причина, поради която използвах глобалните променливи, които направих.   -  person SharpHawk    schedule 10.04.2012


Отговори (5)


Единственият официален термин, който знам за метода, който използвате, е „зависимо от внедряването поведение“. Ще се сблъскате с всякакви проблеми с този метод, след като започнете да създавате с различни компилатори (или евентуално дори различни версии на един и същ компилатор). Някои ще изведат грешка при свързване, но някои ще я приемат (въпреки че няма гаранция как точно ще бъде интерпретирана). Силно ви препоръчвам да приемете по-стандартен подход, който компилаторите ще интерпретират по предвидим начин.

Дефиницията за променлива трябва да бъде в .c файл. Ако искате да получите достъп до тази променлива от друг .c файл, добавете extern декларация в заглавката. Тази техника е стандартна C и ще бъде интерпретирана предсказуемо от всеки съобразен компилатор.

За да отговоря на вашия въпрос за разпределение, паметта за всички глобални се разпределя преди програмата да започне да работи. Глобалната променлива заема място, дори ако се използва само в подраздел на кода, който никога не се изпълнява. Вашият ред globalvariable = 0; всъщност не дава на променливата начална стойност. C компилаторът ще се увери, че всички неинициализирани глобални променливи автоматично се инициализират до нула, когато програмата се зареди. Вашият код технически преназначава стойността на променливата. Ако искате да се уверите, че глобалът е инициализиран към определена стойност, добавете инициализатора към дефиницията като int globalvariable = 42;.

person bta    schedule 09.04.2012
comment
Бях раздвоен между този отговор и този на R.. Този спечели, тъй като отговори на всички части от първоначалния ми пост. - person SharpHawk; 10.04.2012

Проблемът с това е, че може да получите грешки при свързване поради множество дефиниции, когато се опитате да свържете вашата програма. Тук зависи от поведението, дефинирано от внедряването - на изпълнението е разрешено да третира дублиращите се дефиниции като всички препращащи към един обект, но не е задължително.

person Chris Dodd    schedule 09.04.2012

extern int globalvariable;

е декларация

int globalvariable;

е едновременно декларация и предварителна дефиниция.

В C е незаконно една и съща променлива да има множество дефиниции и това ще се случи, ако използвате последната в заглавен файл, който е включен в повече от една единица за превод.

Unix системите обаче исторически позволяват тази употреба, така че повечето компилатори ще приемат кода, въпреки че е невалиден C.

person R.. GitHub STOP HELPING ICE    schedule 09.04.2012
comment
Какво имате предвид под използване на последното в заглавен файл, който е включен в повече от една единица за превод? Дали наличието на множество изходни файлове включва този брой на заглавните файлове? Ако е така, точно това правя и както казахте в последния си ред, компилаторът не се оплаква. Всъщност той дори не извежда предупреждение. - person SharpHawk; 10.04.2012
comment
вярно Компилаторът не може да се оплаче, защото всяка отделна единица за превод е валидна; само линкерът може да се оплаче, но не го прави, защото това е традиционно в unix. Това все още не го прави валиден C и не прави това, което искате. (Той свива множество дефиниции на променливата в една по време на връзката, вместо да декларира, че искате да получите достъп до променлива, дефинирана в друга транслационна единица.) - person R.. GitHub STOP HELPING ICE; 10.04.2012

Недостатъкът на вашия код е, че вероятно ще получите грешка при свързване.1


1. Където „вероятно“ се основава на идеята да изградите своя код върху цял куп различни вериги от инструменти.

person Oliver Charlesworth    schedule 09.04.2012
comment
Наистина ли мислите, че ще продължа да правя нещата по този начин, ако това причинява грешки в линкера? - person SharpHawk; 10.04.2012
comment
@SharpHawk: Пробвал ли си, да речем, MSVC? - person Oliver Charlesworth; 10.04.2012
comment
Не, използвал съм го само в AVR Studio 5 (несъмнено ужасна програма). - person SharpHawk; 10.04.2012

Стандартът ANSI C казва

Ако декларацията на идентификатор за обект има файлов обхват и няма спецификатор на клас за съхранение, връзката му е външна.

person Inquisitive    schedule 20.07.2014