Why are function definitions implicitly external in C?
Asked Answered
R

1

1

I read that the extern keyword is implicit in the context of functions, so unless you specify otherwise using the static keyword (which if I'm not mistaken is basically a completely separate concept from the static that variables employ—they just share a keyword), they are visible to all object files. This makes sense; having the declarations be implicitly external, while technically unnecessary when the declarations are in the same file as the definition, is useful because the programmer doesn't have to type extern every time they want to use a function out of its defining file, which is more often the case than not. What seems odd to me is that it is implicit for the declarations and the definition.

With a variable, I don't need to include an extern for the definition, and in fact, while I can do this without error, my compiler gives me a warning for it.

For example, I can have mylib.h:

int var = 5;

//it isn't necessary to write this as
//extern int var = 5;
//my compiler even warns against it

and test.c

#include "mylib.h"

extern int var;

I would normally assume the implicit extern for functions to be the same, that is, if I defined int func(int par) in mylib.h, there would not be an implicit extern before it, but there would be an implicit extern for any declaration of it (such as if I declared it for use in test.c).

It also doesn't make much sense from the perspective of the extern keyword being used as a way of telling the compiler to look elsewhere for the definition, when the definition would never be external of the file it is in.

I feel like I'm missing something here.

Repetition answered 11/11, 2020 at 7:0 Comment(21)
Maybe I misunderstand your question but it seems to me that you are doing this the wrong way. Putting int var into an h-file and putting extern int var in th c-file is not the usual way. Not sure these to Qs are dupes but I think you'll find the needed info by reading: https://mcmap.net/q/17012/-how-do-i-use-extern-to-share-variables-between-source-files/4386427 and https://mcmap.net/q/15925/-what-is-the-difference-between-a-definition-and-a-declaration/4386427Conferral
If you write int var = 5; in mylib.h, then that defines the variable. In any given program, only one file can include mylib.h — if more than one file includes the header, you get multiply-defined errors. With GCC 10.x, by default, even if you write int var; in a header (rather than extern int var;), you will end up with multiple definition errors — though older versions of GCC did not do that by default.Durarte
For further discussion, see: How do I use extern to share variables between source files? and When to use extern “C” in C++? and When to use extern “C” in simple words?Anxiety
The static keyword for both variables and functions limits the visibility of the named object. There are differences — you can have static variables inside functions, for example. But the concepts are sufficiently similar that saying "[static applied to functions] is basically a completely separate concept from the static that variables employ" is an overstatement at least.Durarte
I'm going off of Beginning C 5th Ed. by Ivor Horton, from apress. It gives the example of int number = 0; double in_to_mm = 2.54; which it places in one file, and the source file accessing the global variables uses extern int number; extern double in_to_mm;Repetition
@Repetition In your comment about the book you write: "... which it places in one file..." Are you sure that is in an h-file? If so it's very strange... but if it's in a c-file, it's okConferral
@4386427 I took a screenshot of the book page imgur.com/a/esV4WpaRepetition
If you are a beginner you should avoid extern entirely. There is very limited use for the keyword in properly designed programs. A few special cases exist, but they are very specialized.Cacia
If the definitions with the initializers are shown in a header file, then throw the book away — now! If it can't get that right, you don't know what else it is mis-teaching you! It would be fine if the definitions with initializers are in a source file, not a header. But all the source files referencing or defining those variables should include the header that declares the variables (extern int number; extern double in_to_mm;).To ensure proper cross-checking, the header should be included by the source file that defines and initializes those variables as well as by those that reference it.Durarte
@Repetition From the picture you linked it's obvious that the book is talking about two different source files (aka c-files). It's not talking about one h-file and one c-file.Conferral
I would argue that making functions externally visible by default in C was a mistake. It would, IMO, be far better if the default was static and you had to explicitly mark the function as visible outside the source file.Durarte
@4386427 I guess I must have falsely assumed that header files were also okay for this. That and I tested the extern int var thing out and the gcc compiler had no error or warning about my putting the definition in the header without extern but including it with the declaration in the source file. Looking at sravs' answer, I guess it's because I only had one header and one source file in my test.Repetition
@4386427 I am a little confused from the perspective of, even using just two different source files, the definition seems to lack an extern and the declaration has one, while in sravs' answer, it looks like it is the other way around where the definition has the keyword and the declarations omit it.Repetition
@Repetition You don't use extern in definitions. You use extern in declarations. The declaration simply says: This variable is defined in some other compilation unit, i.e. in another c-file. The use of extern declaration in h-files is simply to avoid to write the same stuff again and again in multiple c-files.Conferral
@4386427 Oh, okay, I see. I misread sravs' program where my brain again kind of assumed that the definition would go into the header, even though that would cause the conflict of global variables that their answer was warning against anywaysRepetition
@Cacia I see. I sort of assumed that it was more of an 'advanced beginner' concept. Basically, I'm familiar with the absolute basics of stuff like variables, functions, arrays, pointers, loops, conditions, etc. and I'm trying to figure out what comes next.Repetition
@JonathanLeffler regarding the static keyword, I thought that in the context of variables it is used for the purpose preventing the destruction of the variable between instances of running a function and that 'visibility' was more a concept of scope, where it depends on what 'level' of code block you put the variable in (i.e. loops, functions, conditions, etc.).Repetition
@Repetition Read https://mcmap.net/q/591196/-what-a-c-static-variable-in-file-scope-meansConferral
@JonathanLeffler Anyways, regardless of whether the default for functions is to implicitly declare them as static or extern, and regardless of whether it was a mistake or not; I do still wonder, why would the definitions have the implicit extern?Repetition
@4386427 You said you don't use extern for definitions, when we were talking about variables. I'm still kind of confounded by the implicit use in function definitions.Repetition
@Repetition Well, your real question, i.e. "why are functions implicit extern" can probably only be answered by the inventors of C. There is no technical reason as far as I can see. My guess is that they preferred it like that in order to avoid the need of writing extern in a lot of h-files.Conferral
S
2

If you use int x = 10; in any header file, then you are entering into trouble, because if you include the same header file in any other file (.c or .h) that is linked with test.c then you will get an error redefinition of variable x.

You can try that for yourself.

So always keep extern int x; in a header file, and define it int x = 10; in any .c file.

So, in this case, if you include the header file in multiple places, it is fine, because the header file only has a declaration and you can declare the same variable in multiple places without any problem.

you can try this sample program to test the error multiple definition of `global_value'

test.h

extern int global_value;

test.c

#include <stdio.h>
#include "test.h"
int global_value = 10;

int test_func()
{
        printf("golbal_value = %d", global_value);
        global_value = 20; // changed here, reflect in main after test_func call
}

main.c

#include <stdio.h>
#include "test.h"
int main()
{
        test_func();
        printf("global_value = %d\n", global_value);
        return 0;
}

the above program works perfectly. to get the error bring that extern int global_value; to test.c and int global_value = 10; to test.h and compile all together gcc test.c main.c

Sapheaded answered 11/11, 2020 at 7:14 Comment(3)
Thank you, this really helps me get a better understanding of why headers should not contain global variable definitions. So far as I understand, because headers are appended to the source file in preprocessing you basically could run into trouble with having multiple source files each defining that global variable, confusing the compiler. I guess you could theoretically have the same issue if you included the header twice in one source file, if you don't have inclusion guards; though I guess if your header doesn't have inclusion guards, that's a big problem to begin with.Repetition
So, I just thought of something. If there is the issue of global variables conflicting with themselves when defined in header files, does that mean that, given the implicit extern in functions, unless you define a function as static in a header, it would have the same issue? That is, it is better to declare the function in a header, but it is likely to cause issues if it is defined there?Repetition
generally we dont declare static functions in header files because we want to use the static functions in the one single .c not out side of the file. so we declare them in .c itself above all other statements.Sapheaded

© 2022 - 2024 — McMap. All rights reserved.