Author Topic: header file exposure  (Read 4768 times)

0 Members and 1 Guest are viewing this topic.

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17815
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
header file exposure
« on: October 06, 2021, 09:35:38 am »
I want to write a header file that will be used by only one C file and one other header file. Is there a way to limit the visibility of the file? Basically I don't want to write overly long defines to guarantee that they do not clash with something else, but if this file is included in the main header file with function prototypes I will expose it to the whole program.

So I think something like:

name.c - cotains the code
name.h - contains the publicly available function types
name_internal.h - contains the private stuff and is only included in the c file.
 

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 21681
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: header file exposure
« Reply #1 on: October 06, 2021, 09:50:48 am »
It's traditional to put private stuff at the top of the .c file itself; or if you wish to avoid clutter, you can dump that into a "_private.h" or whatever, yes indeed. :)

There's no mechanism to prevent another file including that header, this is all just convention and hackery in C to emulate what would be explicit OOP in a higher level language.

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline Psi

  • Super Contributor
  • ***
  • Posts: 9946
  • Country: nz
Re: header file exposure
« Reply #2 on: October 06, 2021, 10:18:42 am »
There's no mechanism to prevent another file including that header, this is all just convention and hackery in C to emulate what would be explicit OOP in a higher level language.

I've not actually tried this but could you surround your private header with an #ifdef.
Then, when you need to include it you do #define, #include, #undefine ?

If that works it would protect that file in case it is ever included by accident somewhere else in the project.

Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline T3sl4co1l

  • Super Contributor
  • ***
  • Posts: 21681
  • Country: us
  • Expert, Analog Electronics, PCB Layout, EMC
    • Seven Transistor Labs
Re: header file exposure
« Reply #3 on: October 06, 2021, 10:50:15 am »
I mean, whatever song and dance you put into it, can just be copy and pasted from another file into the target file.  Preprocessor isn't quite Turing complete, nor stateful, so you can't implement just anything, like, locking it behind a crypto challenge-response or something.  There's no semantic protection, it's simply the honor system whether something #includes it or not.

Surrounding it with an #ifdef is a good idea anyway, but usually for purposes of including it just once -- this way if several headers include it in turn, there's no confusion.

Tim
Seven Transistor Labs, LLC
Electronic design, from concept to prototype.
Bringing a project to life?  Send me a message!
 

Offline DiTBho

  • Super Contributor
  • ***
  • Posts: 3915
  • Country: gb
Re: header file exposure
« Reply #4 on: October 06, 2021, 11:12:36 am »
name.c - cotains the code
name.h - contains the publicly available function types
name_internal.h - contains the private stuff and is only included in the c file.

rename internals as ".inc"

name.c:
Code: [Select]
#include "name.h"
...
#define _name_internal_
#include "name_internal.inc"

name.h:
Code: [Select]
#ifndef _name_h_
#define _name_h_

...

#endif

this can be used *only* if _name_internal_ is defined, and only name.c should define it
name_internal.inc:
Code: [Select]
#ifdef _name_internal_

...

#endif
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17815
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: header file exposure
« Reply #5 on: October 06, 2021, 11:48:09 am »
what i am thinking is if the contents of a header file is only used in the context of a file it is included into then by only including it in one c file it should only be visible to that one. A reference in a C file to anything in a header file that has not been #include'd in that C file throws an error.
 

Online magic

  • Super Contributor
  • ***
  • Posts: 6779
  • Country: pl
Re: header file exposure
« Reply #6 on: October 06, 2021, 01:26:16 pm »
if this file is included in the main header file with function prototypes I will expose it to the whole program.
Yes. If the main header needs some "internal" #defines then I'm afraid your only option is to #undef all of them at the end of the main header.

If it's possible to extract all stuff dependent on internal #defines into a separate file then sure, do it. Files which don't include the "internal" .h file (directly or via the main / other header) will not see its #defines.
 

Offline dferyance

  • Regular Contributor
  • *
  • Posts: 181
Re: header file exposure
« Reply #7 on: October 06, 2021, 01:56:33 pm »
Header files are to share common declarations and defines between c files. If you don't want it shared, don't put it in a header file. Instead, put it in the c file directly. Yeah you could do some kind of internal header but why? It is just splitting code between files without a design reason for it.
 
The following users thanked this post: Siwastaja

Online PlainName

  • Super Contributor
  • ***
  • Posts: 6843
  • Country: va
Re: header file exposure
« Reply #8 on: October 06, 2021, 06:04:01 pm »
Quote
Yeah you could do some kind of internal header but why? It is just splitting code between files without a design reason for it.

You might want to do that for unit testing. For instance, in your .c you might have:

Code: [Select]
void
clkTickTimer_imp(xTimerHandle pxTimer)
{
...
}

void (*clkTickTimer)(xTimerHandle pxTimer) = clkTickTimer_imp;

and then in a .inc you would have:

Code: [Select]
extern void (*clkTickTimer)(xTimerHandle pxTimer);
Both the .c and your unit test .cpp would then #include whatever.inc

(Magically, your unit test code can now easily hook and redirect calls or other referrals to a function restricted to a specific .c file - the answer to 'design reason for it'. I'm sure there are many more.)

 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9890
  • Country: us
Re: header file exposure
« Reply #9 on: October 06, 2021, 06:05:17 pm »
if this file is included in the main header file with function prototypes I will expose it to the whole program.
Yes. If the main header needs some "internal" #defines then I'm afraid your only option is to #undef all of them at the end of the main header.

If it's possible to extract all stuff dependent on internal #defines into a separate file then sure, do it. Files which don't include the "internal" .h file (directly or via the main / other header) will not see its #defines.

As pointed out above, put the private definitions in the .c file.  If a header file doesn't exist, it can't be used nor the contents exposed unnecessarily.

The .h file should expose only those constants, macros and functions that other functions actually need to know.

Trying to get clever with something like <filename.inc> is not a solution as the file still exists and you have no real way to restrict its use.
« Last Edit: October 06, 2021, 06:07:27 pm by rstofer »
 

Online PlainName

  • Super Contributor
  • ***
  • Posts: 6843
  • Country: va
Re: header file exposure
« Reply #10 on: October 06, 2021, 06:55:25 pm »
Quote
you have no real way to restrict its use.

Frankly, if a header is obviously private and someone nevertheless decides to include it elsewhere, they need sacking, not protecting. Otherwise you're best encrypting your source in case they stick a crafty #extern in their c file, eh.
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17815
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: header file exposure
« Reply #11 on: October 07, 2021, 07:33:04 am »
what I am trying to do is replace register setup values with something meaningful that I can choose to use is a user setup headher that will then be put into the C code. So say I want to have defines for the internal ADC reference voltages. I define 0V55, 1V1, 1V5 etc in the private header, then these can be used in the setup header when I define V_ref, Basically it means I don't need to write one long file where the values the "user" sets up are right at the bottom because I cannot use something until it is defined. But I do not want to clash with any manufacturer definitions or definitions of other peripherals. So I have the internal defines and the setup defines as private to the ADC C file and the prototype functions go in the public ADC header file.

The other way is to use defines or variables in the ADC C file that are using defines in a private header file saving one header file.
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9890
  • Country: us
Re: header file exposure
« Reply #12 on: October 07, 2021, 04:02:48 pm »
Quote
you have no real way to restrict its use.

Frankly, if a header is obviously private and someone nevertheless decides to include it elsewhere, they need sacking, not protecting. Otherwise you're best encrypting your source in case they stick a crafty #extern in their c file, eh.

Which is why file global variables, local to a file but shared among functions in the file should be declared 'static'.  If this is done, they can not be reached by a 'extern' declaration but they can be shared by functions within the file.

Functions within a file can also be declared 'static' in which case they can't be referenced from outside the file.  Not only does this hide the function, it can help prevent name clashes.

C is a pretty good language.  It has all the protection features a programmer should need but they are pretty much worthless if they aren't used.  Bottom line:  Don't expose anything that you don't have to.
« Last Edit: October 07, 2021, 04:07:32 pm by rstofer »
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9890
  • Country: us
Re: header file exposure
« Reply #13 on: October 07, 2021, 04:31:06 pm »
what I am trying to do is replace register setup values with something meaningful that I can choose to use is a user setup headher that will then be put into the C code. So say I want to have defines for the internal ADC reference voltages. I define 0V55, 1V1, 1V5 etc in the private header, then these can be used in the setup header when I define V_ref, Basically it means I don't need to write one long file where the values the "user" sets up are right at the bottom because I cannot use something until it is defined. But I do not want to clash with any manufacturer definitions or definitions of other peripherals. So I have the internal defines and the setup defines as private to the ADC C file and the prototype functions go in the public ADC header file.

The other way is to use defines or variables in the ADC C file that are using defines in a private header file saving one header file.

'getters' and 'setters' - functions that 'get' a value for a user in user units and 'set' a range (or whatever) again, in user units.  These are really common in C++ but they are also a nice way to provide the user interface for C programs.  The user has no need to know how or even where an analog value comes from.  They don't need to know that some 5th order polynomial was used to calculate the value, all they need is the value in user units.  Obviously, the header file will declare the getter and setter functions but that's about all.  The fact that you just changed ADCs doesn't impact the user at all.  User units are user units...  Yes, the getter and setter functions will need to change but that should be local to a single .c file.  If the .h file is properly written, it won't even change when the device changes.

There is no need for a header file that impacts only 1 .c file.  Header files should be used to share information and if it shouldn't be shared, it doesn't belong in a header.  There's simply no reason to avoid putting #defines inside .c files.  That's about as close to the point of use as you can get and makes editing a lot easier.  All the header file should do is declare the functions for external use and, by including in the related .c file, provide a forward declaration of the functions which makes certain that the .c and .h declarations are identical.

Never tell the user anything they don't absolutely need to know!
« Last Edit: October 07, 2021, 04:36:09 pm by rstofer »
 

Online PlainName

  • Super Contributor
  • ***
  • Posts: 6843
  • Country: va
Re: header file exposure
« Reply #14 on: October 07, 2021, 06:36:02 pm »
Quote
'getters' and 'setters' - functions that 'get' a value for a user in user units and 'set' a range (or whatever) again, in user units.

What he said.

Although I suspect the issue will then just move to how the getter/setter implements things. Somewhere along the line there has to be an actual conversion, and it's either a bit of calculation or a ton of defines. Which brings us back to where we were :)
 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17815
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: header file exposure
« Reply #15 on: October 07, 2021, 06:46:07 pm »
Yes I can define the setup values in the c file, that just eliminates one of the header files, there will still be the file that the world sees and the file that only the c file sees.
 

Offline ejeffrey

  • Super Contributor
  • ***
  • Posts: 3717
  • Country: us
Re: header file exposure
« Reply #16 on: October 07, 2021, 08:16:18 pm »
I want to write a header file that will be used by only one C file and one other header file. Is there a way to limit the visibility of the file? Basically I don't want to write overly long defines to guarantee that they do not clash with something else, but if this file is included in the main header file with function prototypes I will expose it to the whole program.

So I think something like:

name.c - cotains the code
name.h - contains the publicly available function types
name_internal.h - contains the private stuff and is only included in the c file.

Just do exactly that then #include both headers from name.c.  You should include name.h first and name_internal.h last.  Nothing you can do can stop someone from importing the definitions of name_internal.h if they really want to, nor can you stop an idiot who is just typing random things in hopes that it will work.  All you can or should try to do is make it less likely for a knowledgeable and well meaning person to do so unintentionally. Being clear with the name and not trying to do anything unnecessarily clever is the way to accomplish this.

If you really want to isolate things compile to name.o and distribute that along with only name.h.

Or just put those private details in the C file.  The purpose of header files is to enable including from multiple locations.  A header file that can only be used from one file is unnecessary.  However, sometimes you may have multiple cooperating C files that need to share the private declarations, then using _private.h makes perfect sense.
« Last Edit: October 07, 2021, 08:19:07 pm by ejeffrey »
 

Offline blacksheeplogic

  • Frequent Contributor
  • **
  • Posts: 532
  • Country: nz
Re: header file exposure
« Reply #17 on: October 07, 2021, 09:07:36 pm »
Yes I can define the setup values in the c file, that just eliminates one of the header files, there will still be the file that the world sees and the file that only the c file sees.

Have you thought about using -DBUILD_ADC_VALUE=12 for example. You can use this as a base definition and make use of it by the preprocessor.

 

Offline SimonTopic starter

  • Global Moderator
  • *****
  • Posts: 17815
  • Country: gb
  • Did that just blow up? No? might work after all !!
    • Simon's Electronics
Re: header file exposure
« Reply #18 on: October 08, 2021, 08:42:38 am »
Well this is me trying to make things for future me. There are no other people involved. Several minutes later I am as clueless about what I just wrote as the next person.
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8172
  • Country: fi
Re: header file exposure
« Reply #19 on: October 08, 2021, 12:16:40 pm »
-D on command line for a few parameters, or those that I need to build different versions with.

For example, if I have two PCB revisions on the field (and those can't be disposed of), then it's -DPCBREV=1B.

Or if you have two versions with different battery voltage and the firmware needs to know what it is to correctly implement battery indication, and you don't want to do it runtime configurable parameter, then -D is your friend, you always know what you are compiling and can quickly do different versions.

For large number of mostly rarely changing constants and #defines, some config.h that can be included from multiple files. Everything must be static const, or #defines, so they work over multiple files. I prefer one such config.h even if these are used in multiple places. Everything here should be truly something that can and will be modified; for stuff where change of constant requires code review or code changes, just define them in the related module (thing.c), close to where they are used. If module becomes too long for you to "find" the constant definitions, don't try to mitigate by moving them to a "common place", instead split the module functionality.

These are all simplifications for small projects on small teams, larger solutions involve configuration scripts (think about configure-make-install pattern).
 

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 151
  • Country: us
Re: header file exposure
« Reply #20 on: October 08, 2021, 04:01:09 pm »
I want to write a header file that will be used by only one C file and one other header file. Is there a way to limit the visibility of the file?

There's no way to prevent a maliciously curious user from `#include`ing your private header file, if they set their mind on doing so.

So, all you can do in this case is give your internal header an "internal sounding" name and/or bury it deeper in a directory structure, i.e. place it into a dedicated directory for "internal" headers.

Of course, you can add an extra layer of protection, like require an extra `#define I_AM_THE_LIZARD_QUEEN` from anyone trying to include your header, just to prevent accidental inclusion. But normally it is not necessary.
« Last Edit: October 09, 2021, 08:37:41 pm by TheCalligrapher »
 

Online PlainName

  • Super Contributor
  • ***
  • Posts: 6843
  • Country: va
Re: header file exposure
« Reply #21 on: October 08, 2021, 05:08:19 pm »
Quote
There's no way to prevent a maliciously curios user from `#include`ing your private header file, if they set their mind on doing so.

Actually...

Just shove a global in there:

Code: [Select]
int  whoopsie;
The compiler/linker will complain if the header is included more than once.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14466
  • Country: fr
Re: header file exposure
« Reply #22 on: October 08, 2021, 05:52:51 pm »
Quote
There's no way to prevent a maliciously curios user from `#include`ing your private header file, if they set their mind on doing so.

Actually...

Just shove a global in there:

Code: [Select]
int  whoopsie;
The compiler/linker will complain if the header is included more than once.

Unfortunately, it may not make the compiler nor the linker complain.
Quote
J.5 Common extensions
J.5.11  Multiple external definitions
There may be more than one external definition for the identifier of an object, with or
without the explicit use of the keyword extern
; if the definitions disagree, or more than
one is initialized, the behavior is undefined (6.9.2).

AFAIR, GCC for instance used to allow multiple definitions of a global variable in older versions. It stopped allowing this by default with relatively "recent" versions.

You can still make it allow multiple definitions using the attribute '__common__'. Such as:

Code: [Select]
__attribute__((__common__)) int  whoopsie;
The '-fcommon' command-line flag should also make GCC allow multiple definitions.

But try with various versions of GCC or other compilers and report back. Problem is, according to the standard, allowing multiple external definitions is a "common extension", which means that your solution is not guaranteed to have the effect you want here.

Even multiple definitions in the same file are allowed - those are called "tentative definitions", and are actually not an extension, but standard. Those must follow certain rules though, such as not having an initializer.
Quote
A declaration of an identifier for an object that has file scope without an initializer, and
without a storage-class specifier or with the storage-class specifier static, constitutes a
tentative definition.

Yeah. C is fun. :-+
 

Online PlainName

  • Super Contributor
  • ***
  • Posts: 6843
  • Country: va
Re: header file exposure
« Reply #23 on: October 08, 2021, 06:36:20 pm »
Quote
Unfortunately, it may not make the compiler nor the linker complain.

Bum. Could've been a neat dirty hack :)

Quote
Quote
or more than
one is initialized

Code: [Select]
int  whoopsie = 1;
« Last Edit: October 08, 2021, 06:38:07 pm by dunkemhigh »
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14466
  • Country: fr
Re: header file exposure
« Reply #24 on: October 08, 2021, 07:30:08 pm »
Quote
Unfortunately, it may not make the compiler nor the linker complain.

Bum. Could've been a neat dirty hack :)

Quote
Quote
or more than
one is initialized

Code: [Select]
int  whoopsie = 1;

As you can read, in this case, the behavior is *undefined*. And for compilers allowing multiple external definitions, they usually don't care one bit if there are initializers or even if the types are different!
You can check this with GCC, either old versions, or passing the '-fcommon' option flag. You'll see for yourself.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf