Definition and declaration of global variables using preprocessor trick - c++

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:)

Related

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.)

C++ Header #define compiler error

I'm learning C++ and I'm at a fairly low level still. - I'm currently looking at using header files and I have a two part question.
Part 1
As I understand them so far, header file definitions are similar to hard coded strings within VB.net? For example I can do the following #define STOCK_QUANTITY 300 and then reference my definition when using it within functions? I assume this works the same way as VB.net strings as I only need to change the value in one place should I need to make changes to the definition and my program references the number 300 on a few hundred different lines?
Part 2
Now, as I said I'm still learning so I'm still doing ye old multiplication tasks. I'm good within using functions with my main .cpp file but I'm not moving on to header files. This is my code snippet thus far.
add.h
#ifndef ADD_H
#define ADD_H
int add(int x, int y);
#endif
main.cpp
#include "stdafx.h"
#include <iostream>
#include "add.h"
int main()
{
using namespace std;
cout << add(3, 4) << endl;
return 0;
}
When trying to run this I receive 2 build errors and it will not compile.
Apologies is these are silly questions, but I would appreciate insight, tips or even some other things I should consider. Thanks.
EDIT
Based on an answer I've changed my add.h too
#ifndef ADD_H
#define ADD_H
int add(int x, int y)
{
return x + y;
}
#endif
As soon as I read the answer I realised I hadn't even told the function what to do :( - Gosh.
You have not added a function body for the function add
int add(int x, int y)
{
// add stuff here
}
This can be done in either the header file, or a seperate cpp file for add. You are trying to call the function that has no code. This is known as a function prototype.
You have only declared that the function add exists, which is why you can call it. But you don't actually define the function anywhere.
In C++ you have to differ between declaration and definition. Sometimes those are done at the same time, like when declaring a local variable. Other times you separate them, like when having a function prototype in a header file (like you do) then that's the declaration. The definition of the function is then the implementation of the function.
After the edit, you now have another problem. And that is if you include the header file in multiple source files, each of those source files (formally known as translation units) will have the function defined and you will get an error because of that.
It can be solved by making the function static or inline. Or better yet, create a new source file (like add.cpp) where you have the definition of the add function, and keep only the declaration (prototype) in the header file.
As for part 1 of your question:
While #defines do as you described, there are some of disadvantages with using them (e.g. They are parsed by the pre-processor, and not by the compiler so no type checking, and also you can get funky errors if you have slightly more complicated macros.
So while your statement is valid, in that it defines a global constant that you only need to modify in one place, and can use in multiple places, for that purpose it is better to have an actual constant variable in the header file:
e.g.
const int STOCK_QUANTITY = 300;
Now you explicitly name it an integer, and also the compiler can perform extra checking.
See also Item 3 in Effective C++ by Scott Meyer (which is a must read in my opinion if you are serious about contineouing programming in c++, although you need allready some experience before reading that.)

How can I use a global variable in C++?

I'm developping a Blackberry 10 mobile app. using the momentics IDE (BB Native SDK).
In my application, I want to use global variables that will be shared by many classes.
I tried the code below like described in this link, but when I add the extern instruction before the declaration of the variable "g_nValue* " in the ".h" file, it returns the error "storage class specified for 'g_nValue'"
*/ global.cpp:
// declaration of g_nValue
int g_nValue = 5;
*/ global.h:
#ifndef GLOBAL_H // header guards
#define GLOBAL_H
// extern tells the compiler this variable is declared elsewhere
extern int g_nValue;
#endif
Any one have an idea on this? I searched a lot and they all said that the extern instruction should not cause any trouble.
An alternative to extern are static variables inside a class:
//.h
struct Globals
{
static int g_global_var;
};
//.cpp
int Globals::g_global_var = 0;
//usage:
Globals::g_global_var;
the extern qualifier only tells the compiler, "this symbol is defined in a different source file" - so the symbol exists, it's safe to use it. You will get a linking error if you actually "lie" about it and don't define the symbol - but that's a different story.
There does not seam to be any problem with the code you showed us.
But here is a link which might help you get a better idea...
You don't declare the variable exteren in the compilation unit it's defined in. You only declare it extern (and don't define it) if you want to use it in other .cpp files (compilation units).
Your code seems fine. Maybe the you have an error elsewhere. Maybe there is a semicolon (;) missing in a line before extern int g_nValue.

Structs inside #define in C++

Being pretty new to C++, I don't quite understand some instructions I encounter such as:
#ifndef BOT_H_
#define BOT_H_
#include "State.h"
/*
This struct represents your bot in the game of Ants
*/
struct Bot
{
State state;
Bot();
void playGame(); //plays a single game of Ants
void makeMoves(); //makes moves for a single turn
void endTurn(); //indicates to the engine that it has made its moves
};
#endif //BOT_H_
What I don't understand is the "#ifndef BOT_H_" and the "#define -- #endif"
From what I gather, it defines a constant BOT_H_ if it's not already defined when the precompiler looks at it. I don't actually get how the struct inside it is a constant and how it is going to let me access the functions inside it.
I also don't see why we're doing it this way? I used C++ a while back and I wasn't using .h files, so it might be something easy I'm missing.
This is known as an include guard, to prevent the contents of a header file from being #included more than once.
That is, it prevents the contents of the header file from being copied into the file that #includes it when it has already #included it before.
The #define isn't defining a constant for the struct, but it's simply defining a constant with no value. If that constant was previously defined, the struct will not be redeclared.
It's called "include guard". It protects you from redefinitions occuring when a header is included more than once. There's also non-standard #pragma once that does the same thing, but might not be supported everywhere.
It does not define a constant whose value is the struct. It defines a constant with an empty value.
It's there so that the content of the header is not included twice. Basically it says something like:
if (!bot_h_included)
{
bot_h_included = true;
// code from the header
}
this is called a header guard it stops the compiler compiling or including the code more than once it is similar to pragma once
Just a side note, I don't recommend using #pragma once I see it a lot in a MVC compatible compilers but just a couple of weeks ago I was working with HP UX and the HP-CC does not support #pragma once, I strongly recommend using #ifndef/#define combinations.

Is this extern harmless?

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.