using struct defined header in another header

Programming, for all ages and all languages.
Post Reply
ggodw000
Member
Member
Posts: 396
Joined: Wed Nov 18, 2015 3:04 pm
Location: San Jose San Francisco Bay Area
Contact:

using struct defined header in another header

Post by ggodw000 »

Doing same practice in C now after some time away.
I defined the struct {} <sName> in file1.h and now needed to define function in file2.h which contains the function prototype such as this:
void fcn1(sName * p1);

As far as I remember including file1.h in file2.h is not an exactly proper practice, instead I included in file2.c which contains function declaration:
void fcn1(sName * p1) {...} but it does not seem to be compile unless explicitly include file1.h in file2.h.
key takeaway after spending yrs on sw industry: big issue small because everyone jumps on it and fixes it. small issue is big since everyone ignores and it causes catastrophy later. #devilisinthedetails
User avatar
iansjack
Member
Member
Posts: 4689
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: using struct defined header in another header

Post by iansjack »

It's perfectly normal practice to include header files in other files, often nested several levels deep. Check Linux and GNU sources, for example. Why would you not do so?
simeonz
Member
Member
Posts: 360
Joined: Fri Aug 19, 2016 10:28 pm

Re: using struct defined header in another header

Post by simeonz »

ggodw000 wrote:As far as I remember including file1.h in file2.h is not an exactly proper practice, instead I included in file2.c which contains function declaration:
void fcn1(sName * p1) {...} but it does not seem to be compile unless explicitly include file1.h in file2.h.
You need "elaborated type specifier". I am not sure that the C standard even uses such terminology, because you always have to elaborate the types anyway. That is, the type name must use the "struct" prefix explicitly, as in "void fcn1(struct sName * p1)". Unless you use a typedef, in which case you can refer to the type without qualification (but it is a different name living in a different identifier namespace - those of typedefs).

Regarding the header inclusion, the practices vary and the general situation is not resolved. Your mileage will vary from project to project and from source to source. Including many headers can gradually accumulate to point where you have longer build times. In C this is less of a problem, but can get pronounced if your headers have a lot of inline functions. The issue is more compounded for C++ with templates, because their syntax is hard to parse and they can be instantiated multiple times in declarations. Anyway, for inline entities the compiler does at least some preliminary parsing of the code and error checking. Another issue that may occur is that you may get cyclic header dependencies. This happens in larger projects.

Note that for function prototypes, you don't need type definitions, but just forward declarations. Those are automatic for structures at the point of their use in the prototypes, so you don't need to include any header at all, although you may want to declare (not define) them globally to avoid gcc warnings. For typedefs, you need the definition in every header in form equivalent to their original definition, but you don't need to have the definition of the type they alias. Some examples with appropriate comments:

file1.h:

Code: Select all

typedef struct sName { int x } tName;
file2.h:

Code: Select all

struct sName; // forward declaration
void fcn1(struct sName *p1); // no need for the sName definition; the declaration above is sufficient
typedef struct sName tName; // typedef must be redefined, but does not need the full sName definition
void fcn1(tName *p1); // typedefs do not need elaboration
struct sNameB { struct sName *ptr; }; // Pointer member does not require the full definition of sName
file3.h:

Code: Select all

#include "file1.h"
struct sNameB { struct sName obj; }; // Sub-object member requires the full type definition, hence the include
file2.c:

Code: Select all

#include "file2.h"
void fcn1(struct sName *p1) { ... } // The function does not need the full sName definition, unless it is going to use sizeof for malloc or directly access the members inside
void fcn1(tName *p1) { ... } // ditto
file4.c:

Code: Select all

#include "file1.h"
void fcn1(struct sName param) { ... } // This function uses by-value parameter and need the full sName definition
User avatar
zaval
Member
Member
Posts: 656
Joined: Fri Feb 17, 2017 4:01 pm
Location: Ukraine, Bachmut
Contact:

Re: using struct defined header in another header

Post by zaval »

Oh, C "good practices" stuff. I have a question related, but don't want to emit a thread for it. Would the OP not mind if I parasite my question here? :lol: anyway, it should be useful for others. In may excuse, I'm gonna say, that me too doesn't see any problems with multilevel header inclusions. just don't forget to wrap it up into #ifndef __HEADER_MY_HEADER_NAME_HEADER_HEADER. for the complier to not choke on with it. :D

My question:
Uefi spec has tons of ugly stuff like below. the ugliness is in the definition loop presented on every such a pair (see below), since, the protocol structure has function pointers inside, and every that function has a pointer to this protocol as a parameter.
Just look at this cuteness.
here, we have a definition of the protocol structure with function pointers inside:

Code: Select all

typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL{
    EFI_INPUT_RESET            Reset;
    EFI_INPUT_READ_KEY     ReadKeyStroke;
    EFI_EVENT                      WaitForKey;
} EFI_SIMPLE_TEXT_INPUT_PROTOCOL;
and below, we have those function pointers defintions, eg EFI_INPUT_RESET:

Code: Select all

typedef EFI_STATUS (EFIAPI *EFI_INPUT_RESET) (
    IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
    IN BOOLEAN ExtendedVerification
);
this c++-ish "this" draws me crazy, as to why why on this planet one would need to have it past to every freaking function?! but well, it's a weird and ugly specification requirement. The question is what the most ellegant way to break this definition loop is? how would you resolve it, if you were to forge real headers for it? not just plain dumb hell stupid excerpts full of typos and this mentioned prettiness as in the spec? :)
ANT - NT-like OS for x64 and arm64.
efify - UEFI for a couple of boards (mips and arm). suspended due to lost of all the target park boards (russians destroyed our town).
simeonz
Member
Member
Posts: 360
Joined: Fri Aug 19, 2016 10:28 pm

Re: using struct defined header in another header

Post by simeonz »

I don't know how to produce elegance, but it should resolve with something like this:

Code: Select all

typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL EFI_SIMPLE_TEXT_INPUT_PROTOCOL;

typedef EFI_STATUS (EFIAPI *EFI_INPUT_RESET) (
    IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
    IN BOOLEAN ExtendedVerification
);

typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL{
    EFI_INPUT_RESET            Reset;
    EFI_INPUT_READ_KEY     ReadKeyStroke;
    EFI_EVENT                      WaitForKey;
} EFI_SIMPLE_TEXT_INPUT_PROTOCOL;
User avatar
zaval
Member
Member
Posts: 656
Joined: Fri Feb 17, 2017 4:01 pm
Location: Ukraine, Bachmut
Contact:

Re: using struct defined header in another header

Post by zaval »

simeonz wrote:I don't know how to produce elegance, but it should resolve with something like this:

Code: Select all

typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL EFI_SIMPLE_TEXT_INPUT_PROTOCOL;

typedef EFI_STATUS (EFIAPI *EFI_INPUT_RESET) (
    IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
    IN BOOLEAN ExtendedVerification
);

typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL{
    EFI_INPUT_RESET            Reset;
    EFI_INPUT_READ_KEY     ReadKeyStroke;
    EFI_EVENT                      WaitForKey;
} EFI_SIMPLE_TEXT_INPUT_PROTOCOL;
you are right, it works, let's forget about elegance. :lol: thanks.)

This way it works too:

Code: Select all

typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL EFI_SIMPLE_TEXT_INPUT_PROTOCOL;

typedef EFI_STATUS (EFIAPI *EFI_INPUT_RESET) (
    IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
    IN BOOLEAN ExtendedVerification
);

struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL{
    EFI_INPUT_RESET            Reset;
    EFI_INPUT_READ_KEY     ReadKeyStroke;
    EFI_EVENT                      WaitForKey;
};
but honestly, I don't get it - if it can see yet not defined structure as in the above, why it couldn't see yet not typedefed type name?
well.
I was thinking about something like that:

Code: Select all

typedef struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL{
	EFI_STATUS (EFIAPI *Reset)(struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL *, BOOLEAN);
        /* snip */
}EFI_SIMPLE_TEXT_INPUT_PROTOCOL;

typedef EFI_STATUS (EFIAPI *EFI_INPUT_RESET)(
	IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL	*This,
	IN BOOLEAN				ExtendedVerification
);
but it doesn't look elegant and a typedef'ed function pointer is useless.
Last edited by zaval on Tue Aug 15, 2017 6:30 pm, edited 1 time in total.
ANT - NT-like OS for x64 and arm64.
efify - UEFI for a couple of boards (mips and arm). suspended due to lost of all the target park boards (russians destroyed our town).
User avatar
Geri
Member
Member
Posts: 442
Joined: Sun Jul 14, 2013 6:01 pm

Re: using struct defined header in another header

Post by Geri »

ggodw000 wrote:As far as I remember including file1.h in file2.h is not an exactly proper practice
you can include anything you want anywhere

i personally usually use very few files to avoid these problems.
Operating system for SUBLEQ cpu architecture:
http://users.atw.hu/gerigeri/DawnOS/download.html
simeonz
Member
Member
Posts: 360
Joined: Fri Aug 19, 2016 10:28 pm

Re: using struct defined header in another header

Post by simeonz »

zaval wrote:if it can see yet not defined structure as in the above, why it couldn't see yet not typedefed type name?
To my knowledge, the justification concerns some ancient architectures, which couldn't address individual bytes. As a result, they had to simulate "char *" by extending the pointer with a few additional bits. This heritage remained, in the sense that struct pointers are comparatively interchangeable (with the assumption that they will be properly aligned if need be), but pointers in general need not be. As a consequence, because a typedef may alias structs and non-structs (such as structs and chars on these archaic machines), the corresponding typedef pointer may take different space, depending. I don't think that the same justification applies in prototypes, but the language probably was symmetrical here. I don't know if any modern architecture requires this distinction, but if we are talking about exotic targets, what is the guarantee then that structure pointers will not be different as well.
simeonz
Member
Member
Posts: 360
Joined: Fri Aug 19, 2016 10:28 pm

Re: using struct defined header in another header

Post by simeonz »

zaval wrote:I was thinking about something like that:
This SO post may interest you (only thematically; it did not end productively). The OP is essentially asking, why does C need to know the exact function prototype in all contexts, whereas the forward declaration of a structure is sometimes sufficient. For your case, with some imagined function forward declaration facility, the code could look like this:
zaval wrote:typedef (* EFI_INPUT_RESET)(); //Non-existent forward function pointer type declaration

struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL{
EFI_INPUT_RESET Reset;
EFI_INPUT_READ_KEY ReadKeyStroke;
EFI_EVENT WaitForKey;
};

//Here follows the full type definition of the pointer type
typedef EFI_STATUS (EFIAPI *EFI_INPUT_RESET) (
IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
);
Per the C standard, function pointer types have equally expressive representation, just like struct pointer types, in that they can be converted into each other and back without losing information. If this justifies the usage of struct forward declarations in purely syntactical contexts, such as pointer and signature types, then it should justify function forward declarations as well. Not that it matters if that were true or not. A language standard cannot be expected to be perfect.
User avatar
zaval
Member
Member
Posts: 656
Joined: Fri Feb 17, 2017 4:01 pm
Location: Ukraine, Bachmut
Contact:

Re: using struct defined header in another header

Post by zaval »

thank you. i am just satisfied with the solution you suggested yesterday. it requires lesser amount of modifications and looks quite nice.)
ANT - NT-like OS for x64 and arm64.
efify - UEFI for a couple of boards (mips and arm). suspended due to lost of all the target park boards (russians destroyed our town).
ggodw000
Member
Member
Posts: 396
Joined: Wed Nov 18, 2015 3:04 pm
Location: San Jose San Francisco Bay Area
Contact:

Re: using struct defined header in another header

Post by ggodw000 »

thanks all, perhaps including in another H will be just fine.
key takeaway after spending yrs on sw industry: big issue small because everyone jumps on it and fixes it. small issue is big since everyone ignores and it causes catastrophy later. #devilisinthedetails
Post Reply