OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 1:56 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 11 posts ] 
Author Message
 Post subject: using struct defined header in another header
PostPosted: Tue Aug 15, 2017 12:36 pm 
Offline
Member
Member

Joined: Wed Nov 18, 2015 3:04 pm
Posts: 396
Location: San Jose San Francisco Bay Area
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


Top
 Profile  
 
 Post subject: Re: using struct defined header in another header
PostPosted: Tue Aug 15, 2017 12:56 pm 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4591
Location: Chichester, UK
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?


Top
 Profile  
 
 Post subject: Re: using struct defined header in another header
PostPosted: Tue Aug 15, 2017 2:25 pm 
Offline
Member
Member

Joined: Fri Aug 19, 2016 10:28 pm
Posts: 360
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:
typedef struct sName { int x } tName;

file2.h:
Code:
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:
#include "file1.h"
struct sNameB { struct sName obj; }; // Sub-object member requires the full type definition, hence the include

file2.c:
Code:
#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:
#include "file1.h"
void fcn1(struct sName param) { ... } // This function uses by-value parameter and need the full sName definition


Top
 Profile  
 
 Post subject: Re: using struct defined header in another header
PostPosted: Tue Aug 15, 2017 4:50 pm 
Offline
Member
Member
User avatar

Joined: Fri Feb 17, 2017 4:01 pm
Posts: 640
Location: Ukraine, Bachmut
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:
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:
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).


Top
 Profile  
 
 Post subject: Re: using struct defined header in another header
PostPosted: Tue Aug 15, 2017 5:32 pm 
Offline
Member
Member

Joined: Fri Aug 19, 2016 10:28 pm
Posts: 360
I don't know how to produce elegance, but it should resolve with something like this:
Code:
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;


Top
 Profile  
 
 Post subject: Re: using struct defined header in another header
PostPosted: Tue Aug 15, 2017 5:57 pm 
Offline
Member
Member
User avatar

Joined: Fri Feb 17, 2017 4:01 pm
Posts: 640
Location: Ukraine, Bachmut
simeonz wrote:
I don't know how to produce elegance, but it should resolve with something like this:
Code:
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:
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:
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.

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


Last edited by zaval on Tue Aug 15, 2017 6:30 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: using struct defined header in another header
PostPosted: Tue Aug 15, 2017 6:19 pm 
Offline
Member
Member
User avatar

Joined: Sun Jul 14, 2013 6:01 pm
Posts: 442
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


Top
 Profile  
 
 Post subject: Re: using struct defined header in another header
PostPosted: Tue Aug 15, 2017 6:52 pm 
Offline
Member
Member

Joined: Fri Aug 19, 2016 10:28 pm
Posts: 360
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.


Top
 Profile  
 
 Post subject: Re: using struct defined header in another header
PostPosted: Wed Aug 16, 2017 1:55 am 
Offline
Member
Member

Joined: Fri Aug 19, 2016 10:28 pm
Posts: 360
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.


Top
 Profile  
 
 Post subject: Re: using struct defined header in another header
PostPosted: Wed Aug 16, 2017 3:43 pm 
Offline
Member
Member
User avatar

Joined: Fri Feb 17, 2017 4:01 pm
Posts: 640
Location: Ukraine, Bachmut
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).


Top
 Profile  
 
 Post subject: Re: using struct defined header in another header
PostPosted: Mon Aug 21, 2017 4:47 pm 
Offline
Member
Member

Joined: Wed Nov 18, 2015 3:04 pm
Posts: 396
Location: San Jose San Francisco Bay Area
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


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 11 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 35 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group