You can check this with GCC
That's what made me think of it - I got caught with exactly this issue the other day when including a private header in a unit test module.
it also goes wrong with Linux. When people redefine a critical constant and things start breaking but not immediately because for some weird reasons there is still the old definition around and it's the right order. But then someone removes the file and the kernel compiles but it doesn't even show a line on the console ...
... that is precisely when C is "funny"
I wasted two weeks on such a stupid thing, because I had no idea that was the problem, so I checked other things.
I'm not making it super idiot proof, it only for future idiot me. If someone wants to include my file in the future I would at least expect them to read it and the first line will say that it is private to the C file it belongs to.
I'm not making it super idiot proof
Well, quite. This kind of thing should be aimed at preventing accidental or unwitting screwups. There has to be an assumption that the user is at least semi-competent, and if he isn't then that's his problem. We ain't the police or bodyguards.
There could have been a way using the preprocessor - at least with GCC.
GCC has a number of non-standard predefined macros. The one which could help here is '__BASE_FILE__'. Within the scope of an included file, it holds the name of the base file - the file that includes it.
It's unfortunate though that you can't use string literals in preprocessor comparisons.
Something like this, placed in the header file in question, assuming the .c file in which it's only allowed to be included is name 'allowed.c', would have been a candidate:
#if __BASE_FILE__ != "allowed.c"
#error Included in the wrong file!
#endif
But the preprocessor can't use string literals in this context, so it just gives an error (token ""allowed.c"" is not valid in preprocessor expressions). That's too bad.
Now if you can find a clever way of using this '__BASE_FILE__' macro to achieve the same result, there you go...
a way using the preprocessor - at least with GCC.
I think using a compiler-specific feature may cause more problems than it solves. Whatever solution is used (even if that's "DNF") it needs to work with any standard-compliant compiler, and hopefully most that are more-or-less C.
Now a simple approach not requiring anything non-standard would just be the following:
Add this in the header file 'xxxx.h':
#ifndef ALLOWED_FILE
#error Included in the wrong file!
#endif
To include it in another file:
#define ALLOWED_FILE
#include "xxxx.h"
Failing to define the 'ALLOWED_FILE' macro (name it as appropriate) before including the header file will yield an error.
So to include it, you have to explicitely define this macro. That should be enough to prevent unintended including, and would further self-document where it is appropriate to include it.
I don't really need to guard from it being included by mistake.
That should be enough to prevent unintended including, and would further self-document where it is appropriate to include it.
I reckon that passes the test
Might have already been mentioned here but what I do is take advantage of the include directory flags for the pre-processor. Ie
project
- module1
- module1.c
- internal1.h
- module2
- module2.c
- internal2.h
- include
- public.h
Assuming gcc... `gcc -c -Iinclude module1/module1.c -o module1/module1.o`
Because the private internal header of module2 is not in the include path, unless someone uses a nasty `../` in their include path they can't directly access the private header of another module.
Very funny.
You want not use long names, instead you want short defines, and you are worryd that they overrule some other define.
1 : Are you really typing ?, i use ctrl C + V mostly.
2 : You want two of the same defines that each file have a different function for the define, confusing.
3 : Programming most time-consuming and most-difficult task is making names for your variables.
You can instantly spot amateur code by the defines or no defines at all.
My advantage is i can use two languages for defines and variables.