Is this extern harmless? - c++

main.h
extern int array[100];
main.c
#include "main.h"
int array[100] = {0};
int main(void)
{
/* do_stuff_with_array */
}
In the main.c module, the array is defined, and declared. Does the act of also having the extern statement included in the module, cause any problems?
I have always visualized the extern statement as a command to the linker to "look elsewhere for the actual named entity. It's not in here.
What am I missing?
Thanks.
Evil.

The correct interpretation of extern is that you tell something to the compiler. You tell the compiler that, despite not being present right now, the variable declared will somehow be found by the linker (typically in another object (file)). The linker will then be the lucky guy to find everything and put it together, whether you had some extern declarations or not.
To avoid exposure of names (variables, functions, ..) outside of a specific object (file), you would have to use static.

yea, it's harmless. In fact, I would say that this is a pretty standard way to do what you want.
As you know, it just means that any .c file that includes main.h will also be able to see array and access it.

Edit
In both C and C++, the presence of extern indicates that the first declaration is not a definition. Therefore, it just makes the name available in the current translation unit (anyone who includes the header) and indicates that the object referred to has external linkage - i.e. is available across all the translation units making up the program. It's not saying that the object is necessarily located in another translation unit - just that 'this line isn't the definition'.
End edit
In C, the extern is optional. Without it, the first declaration is a 'tentative definition'. If it were not for the later definition (which is unambiguously a definition because it has an initializer), this would be treated as a definition (C99 6.9.2). As it is, it's just a declaration and does not conflict.
In C++, the extern is not optional - without it, the first declaration is a definition (C++03 3.1) which conflicts with the second.
This difference is explicitly pointed out in Annex C of C++:
"Change: C++ does not have “tentative definitions” as in C
E.g., at file scope,
int i;
int i;
is valid in C, invalid in C++."

The extern is harmless and correct. You couldn't declare it in the header without extern.
As an extra, usually it is best practice to create a macro or a constant to hold the size of the array; in your code the actual size (100) appears twice in the source base. It would be cleaner to do it like this:
#define ARRAY_SIZE 100
extern int array[ARRAY_SIZE];
...
int array[ARRAY_SIZE] = { 0 };
But maybe you did not want to include this in the code snippet just for the sake of brevity, so please take no offense :)

From a compilation or execution point of view, it makes no difference.
However, it's potentially dangerous as it makes array[] available to any other file which #includes main.h, which could result in the contents of array[] being changed in another file.
So, if array[] will only ever be used in main.c, remove the line from main.h, and declare array[] as static in main.c.
If array[] will only be used in the main() function, declare it in there.
In other words, array[] should have its scope limited to the smallest possible.

Related

One-liner extern "C" for a variable - legit?

Consider the following translation unit:
extern "C" int x = 1;
I know that C-mangling an int doesn't mean much; and that int x = 1 already guarantees external linkage, but this should work. Which it does; the thing is, GCC warns about using it, while clang doesn't: See this on GodBolt.
Which compiler is "right"?
How strongly, if it all would you advise avoiding such code?
According to the standard at [dcl.link.2]
Linkage between C++ and non-C++ code fragments can be achieved using a linkage-specification:
linkage-specification:
extern string-literal { declaration-seq }
extern string-literal declaration
Both brace-enclosed and as a prefix to a single declaration are valid.
Which compiler is correct? I'd say both, as they both accept the code and do the correct thing with it.
GCC's warning is just that, a warning. This is the same kind of warning as a "named parameter is not used anywhere": Information about something unusual, but not affecting the behavior of the program.
Both compilers are correct to compile the code without error.
gcc's warning 'x' initialized and declared 'extern' makes sense as well. "extern" declarations, including extern "C" ones, usually go in header files. Initializing in the header file will get you a multiple-definitions error at link time.
If you use the usual pattern, gcc will not give you any warning:
(in header) extern "C" int x;
(in one source file) int x = 1;
Your question says that you're doing this inside one compilation unit. That's not illegal under the language rules, but it is very sketchy.
Either you aren't using the variable in any other compilation unit (in which case it doesn't need linkage at all, let alone "C" linkage) or else you are repeating the declaration in other compilation units, which risks having a mismatch on the type or language linkage.
Putting declarations in header files in a good practice because it prevents type mismatch across compilation units, which is instant undefined behavior.

I'm having an 2D Array Redefinition Error

There is an error (actually 3 same errors) with my definition array int mang[max][max] and I couldn't find anything to fix it properly, so I hope someone will notice my question and help me soon. XD
In my header file array.h, I have:
#include <iostream>
#define max 100
using namespace std;
int mang[max][max];
void NhapMang(int mang[][max], int hang, int cot);
void XuatMang(int mang[][max], int hang, int cot);
int TinhTongPhanTu(int mang[][max], int hang, int cot);
int DemPhanTux(int mang[][max], int hang, int cot);
When I was typing my code, VS shows me that there is "no issues found" all over .cpp files, but when I debug the code, the error appears in the header file array.h, says "C2086 'int mang[100][100]': redefinition" altogether.
I think that I've defined mang twice or more, but I couldn't find the other mang definition nor fixing it if I found. This is the capture of the error list.
I don't know what parts I need provide to you in my project to help fixing it for me (and I also think my post would become so long to read if I copy-paste all my code up here :-( ), so if you need any further information, just comment and I will give it to you.
And well, I've just start learning C++ for 3 months, so there's soooo many things I haven't known yet XD If there's anything I couldn't understand in the way you fix the problem, please let me ask you more about it.
Hope you understand what I mean XD (cuz I'm not a native speaker). And thank you for reading.
The language rules say:
[basic.def.odr]
Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program outside of a discarded statement; no diagnostic required. ...
(There are some exceptions with limitations that are listed in further rules, but none that apply to your example)
int mang[max][max];
This is definition of a variable. That definition is in a header file. Header files are typically included into multiple translation units. If you do so, then you have included the definition of the variable into multiple translation units. By having multiple definitions of a non-inline variable, you would violate the rule quoted above.
The key here is that the pre-processor is a text altering engine. In every file where you have #include "array.h", the textual contents of array.h are inserted in place of the #include.
So, if you have several files that include array.h then each one of those files declares and defines mang (all using the same definition). That isn't a problem during compilation because each file is compiled separately, but they each generate an object file that defines mang.
Then you try to link, and the linker sees several defitions of the array.
The solution is the same as the one you are using for functions in array.h: you declare in the header and define in the implementation (presumably array.cpp).
How do you declare an array without defining it?
Good question. I'm glad you asked. You do it with the extern keyword like this.
array.h:
// ...
#define max 100
extern int mang[max][max]; // <=== Look here (with extern)
// ...
Then you define it in array.cpp:
// ...
int mang[max][max]; // <== and compare to this (no extern)
// ..
As an aside you using the pre-processor to define constants (like #define max 100 has several downsides, and in c++ you are generally better off using compile-time constants like
const int max = 100; // Pre c++11
or
constexpr int max = 100; // c++11 or later
(The use of the pre-processor for this is a holdover from ancient days when compilers were a lot less clever.)

variable must be absolutely global all over sources

How do we make a variable global across over all .cpp files/modules of a (will-be) single binary, which is to be compiled and linked by g++ in a line?
even if it's been defined in main and has extern in var. to be included in every .cpp
extern int a_sample_var;
tried it for more a week only to fail,
.....: undefined reference to a_sample_var .....
Any generous guru helping me out?
extern int a_sample_var;
Tells the compiler: there is a int named a_simple_var defined somewhere else (think about the keyword extern: it's abbreviation for external, meaning "somewhere else"). Just leave a placeholder there and wait for the linker to find it!
Well if you do this in every cpp file (by including a header), then everyone is crying for the definition (by providing a declaration), but with no one to provide the definition. Be aware of the wording here, definition and declaration are different stuff.
In exactly one cpp file, you shall provide a definition of a_simple_var. Just simply remove the extern:
int a_sample_var; // Initialize with 0
or
int a_sample_var = 1; // Initialize with 1.
Those two are proper definitions.

Definition and declaration of global variables using preprocessor trick

I am currently looking through the code written by senior engineer. The code works fine but i am trying to figure out one detail.
He uses quite a few global variables and his code is broken down into a lot of separate files. So he uses a technique to make sure that global vars are declared everywhere where he needs to access them but are only defined once.
The technique is new to me but I read few articles on the internet and got some understanding about how it works. He uses
#undef EXTERN
followed by conditional definition of EXTERN as an empty string or actual extern. There is a very good article here explaining how it works. Also there is a discussion here
What gets me confused is that all examples I saw on the web suggest to include header file in a regular way in all of the source files that need it except for one. In this single special case line that includes header is preceded by definition of a symbol that will ensure that EXTERN will be defined to an empty string and .. so on (see link above). Typically this single special case is in main or in a separate source file dedicated to the declaration of global variables.
However in the code that I am looking at this special case is always in the source file that corresponds the header. Here is the minimal example:
"peripheral1.h" :
#undef EXTERN
#ifndef PERIPHERAL_1_CPP
#define EXTERN extern
#else
#define EXTERN
#endif
EXTERN void function1(void);
"peripheral1.cpp" :
#define PERIPHERAL_1_CPP
#include "peripheral1.h"
function1()
{
//function code code here
}
Everywhere else in the code he just does
#include "peripheral1.h"
My question is how and why does that work? In other words, how does compiler know where to define and where to just declare function (or variable, or class ...)? And why is it ok in above example to have the lines :
#define PERIPHERAL_1_CPP
#include "peripheral1.h"
in actual peripheral1.cpp rather then in main.cpp or elsewhere?
Or am I missing something obvious here?
All the source files, except "perripheral1.cpp", after preprocessing contain a sequence
of external variable declarations like:
extern int a;
extern int b;
extern int c;
In peripheral1.cpp only, after preprocessing, there will be a sequence of declarations:
int a;
int b;
int c;
int d;
which are tentative definitions of the corresponding variables, which, under normal circumstances are equivalent of the external definitions :
int a = 0;
int b = 0;
int c = 0;
int d = 0;
End result is, variable are declared everywhere, but defined only once.
PS. To be perfectly clear ...
In other words, how does compiler know where to define and where to
just declare function (or variable, or class ...)?
The compiler knows where to declare, whenever it encounters a grammatical construct, which is defined in the standard to have the semantics of a declaration.
The compiler knows where to define, whenever it encounters a grammatical construct, which is defined in the standard to have the semantics of a definition.
In other other words, the compiler does not know - you tell it explicitly what you want it to do.
Nostalgia
Ahh, this takes me back a fair way (about 20 years or so).
This is a way for C code to define global variables across multiple files: you define the variable once using a macro to ensure it is defined exactly only once, and then extern it in other C code files so you can utilise it. Nowadays it is quite superfluous in many instances, however it still has its place in legacy code, and will (most likely) still work in many modern compilers, nut it is C code not C++.
Normally the likes of #define PERIPHERAL_1_CPP is utilised to ensure uniquenesss of inclusion like a #pragma once
In my own code I would use something like:
#ifndef PERIPHERAL_1_CPP
#define PERIPHERAL_1_CPP
// my includes here
// my code here
#endif
That way you can #include the file as many times as you want all over your code, in every code file even, and you will avoid multiple definition errors. To be fair I normally do it with the .h files and have something like:
// for absolutely insane safety/paranoia
#pragma once
// normally sufficient
#ifndef PERIPHERAL_1_H
#define PERIPHERAL_1_H
// my includes here
// my code here
#endif
I have never tried it on cpp files but wil llater tonight to see if there is any benefit one way or the other:)
Give me a shout if you need any more info:)

C++ accessing variables from .CPP files

I'm a little fuzzy on how variable access between .cpp files works. For instance:
main.cpp
int main()
{
int a = i;
return 0;
}
main2.cpp
int i;
This generates a compiler error on main.cpp, telling me there is no in i in existence. What difference then, does the "static" keyword do in this context? (I tried Googling for it, but most of the "static keyword" info pages talk about classes & functions)
main2.cpp
static int i;
Is it the same? Does it prevent extern int i being used to access i elsewhere? How does the use of anonymous namespaces differ in how variables are handled?
main2.cpp
namespace
{
int i;
}
To sum up:
Can variables be accessed between .cpp files? (aside from extern keyword)
How does the static keyword on a global variable affect things?
How do anonymous namespaces affect things differently?
In your first example, main2.cpp defines a global variable i, which could have been accessed by main.cpp if an extern declaration of i had appeared in that file. (Normally that extern declaration would come from a header file.) You got a compiler error because i had never been declared in main.cpp, which means the compiler assumes there is no such variable.
In your second example, main2.cpp defines a file scope variable i. File scope variables are distinct from globals, even if they happen to have the same name. If you had had an extern declaration of i in main.cpp in the second example, both files would have compiled successfully, but then you would have gotten a link error because no global variable i was defined.
If you renamed main2.cpp from the second example to main3.cpp, added an extern declaration of i to main.cpp, compiled all three and linked them all together, that would succeed; main.cpp and main2.cpp would share one variable named i, and main3.cpp would have its own entirely separate variable also named i.
This stuff is called linkage. Namespaces are almost entirely unrelated to linkage. However, the anonymous namespace is special. Defining a variable in an anonymous namespace is for all practical purposes the same as defining it with static -- it makes it a file scope variable. (If I remember correctly, there is a difference, but it only matters if you are doing complicated things with exported templates, and as exported templates are so little used that they're talking about deleting the feature from the C++ standard, you don't have to worry about it.)
The value of the anonymous namespace is that you can put a class definition inside it, and that makes all of the class's methods be file-local. (Only the class { ... } block has to be inside the namespace { ... } block to get this effect.) You can't do that any other way.
All global variables have some kind of linkage. extern linkage is required to name the same variable in different contexts between different files.
extern is the default. If you actually use extern in a variable declaration, it's treated as a reference to another file. Omit any linkage specifier to actually create the variable; this must happen in only one file.
extern int i; // i exists somewhere in some .cpp file.
int i; // ah! this is the file it exists in.
// (Although nothing special about that.)
static applied to a global (at namespace scope) makes it local to the file. You get the same effect from a private namespace, so static outside function or class scope is deprecated. Many still use it though.
The exception to the rule of static meaning file-local is in classes and inline functions. Class static members should more properly be called extern since the semantics are identical. It's ugly and confusing, but I guess Bjarne just wanted to eliminate extern as a keyword.
Inline functions can have the same definition among multiple .cpp files, so when one creates a static variable, the variable definition is shared as well.
yes, for example you can use static class variables
it makes variable local and persistent to compilation unit
anonymous namespace prevents collision between symbols. it is as if you create uniquely named namespace manually