Discussion:
"PORTING C" > Inclusion not consistent.
(too old to reply)
Robby
2009-12-26 17:56:01 UTC
Permalink
Hello,

This is interesting.... to me anyways.


#1) We know that we are allowed to *declare* a function prototype in a
header like this:

LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam);

#2) We know we are allowed to include a header file in several .c files.

Having said this, there is an inconsistency that stands out here. Probably
my fault again, but nontheless, I am stumped.

Please carefully view the small program sample:
=========================KERNEL.h
typedef long *LRESULT;
typedef long WPARAM;
typedef long LPARAM;

typedef struct tagHwnd {
long caption_msg;
} HWND;

typedef struct tagMsg {
HWND hwnd;
long msg;
WPARAM wParam;
LPARAM lParam;
long time;
} KM_MSG;

typedef LRESULT(*callBack)(HWND hwnd, long message, WPARAM w, LPARAM l);

LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam);
=========================KERNEL.c
#include <stdio.h>
#include "KERNEL.h"
callBack cb[1];

int main(void)
{
KM_MSG m; HWND hwnd;
hwnd.caption_msg = 1; m.msg = 1; m.lParam = 2; m.wParam = 3;
cb[0] = CALLBACK_WP_INTRO;
CALLBACK_WP_INTRO(hwnd, m.msg, m.wParam, m.lParam);
}
=========================WP_INTRO.h
// no code!

=========================WP_INTRO.c
#include "KERNEL.h"

LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam)
{
return 0;
}
==================================

As you can very well see, the following function prototype:

LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam);

is included twice. The first time by KERNEL.c and the second time by the
WP_INTRO.c from the following inclusion command:

#include "KERNEL.h"

Now, this compiles... no errors and no warnings.

//////////////////////////////////////////////////////////////

But now consider the following small program sample where the same prototype
function is still included twice.... still using the #include pre-proccesor
directives. however this time it generating errors ????

=========================KERNEL.h
typedef long *LRESULT;
typedef long WPARAM;
typedef long LPARAM;

typedef struct tagHwnd {
long caption_msg;
} HWND;

typedef struct tagMsg {
HWND hwnd;
long msg;
WPARAM wParam;
LPARAM lParam;
long time;
} KM_MSG;

typedef LRESULT(*callBack)(HWND hwnd, long message, WPARAM w, LPARAM l);

=========================KERNEL.c
#include <stdio.h>
#include "KERNEL.h"
#include "WP_INTRO.h"
callBack cb[1];

int main(void)
{
KM_MSG m; HWND hwnd;
hwnd.caption_msg = 1; m.msg = 1; m.lParam = 2; m.wParam = 3;
cb[0] = CALLBACK_WP_INTRO;
CALLBACK_WP_INTRO(hwnd, m.msg, m.wParam, m.lParam);
}
=========================WP_INTRO.h
LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam);
=========================WP_INTRO.c
#include "WP_INTRO.h"
#include "KERNEL.h"

LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam)
{
return 0;
}
====================================

Again, as you can very well see, the following function prototype:

LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam);

is also included twice. The first time by KERNEL.c with the following
inclusion:

#include "WP_INTRO.h"

and the second time by the WP_INTRO.c from the following inclusion command:

#include "WP_INTRO.h"

But this time I get the following errors:

1>c:\_dts_programming\pic\_microchip_issues\vc++\function_pointers\function_pointers\wp_intro.h(1)
: error C2061: syntax error : identifier 'CALLBACK_WP_INTRO'
1>c:\_dts_programming\pic\_microchip_issues\vc++\function_pointers\function_pointers\wp_intro.h(1) : error C2059: syntax error : ';'
1>c:\_dts_programming\pic\_microchip_issues\vc++\function_pointers\function_pointers\wp_intro.h(1)
: error C2146: syntax error : missing ')' before identifier 'hwnd'
1>c:\_dts_programming\pic\_microchip_issues\vc++\function_pointers\function_pointers\wp_intro.h(1) : error C2061: syntax error : identifier 'hwnd'
1>c:\_dts_programming\pic\_microchip_issues\vc++\function_pointers\function_pointers\wp_intro.h(1) : error C2059: syntax error : ','
1>c:\_dts_programming\pic\_microchip_issues\vc++\function_pointers\function_pointers\wp_intro.h(1) : error C2059: syntax error : ')'

The reason why I am trying to code it this way, is that I was trying to
include the function prototype in the correct header which belongs to the
respective .c file.
For example, *I think* all function prototypes should be declared in the
specific header which is included by a .c file which carries the function's
definitions.

All help appreciated!
--
Best regards
Roberto
Robby
2009-12-26 18:42:01 UTC
Permalink
Post by Robby
Hello,
This is interesting.... to me anyways.
#1) We know that we are allowed to *declare* a function prototype in a
LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam);
#2) We know we are allowed to include a header file in several .c files.
Having said this, there is an inconsistency that stands out here. Probably
my fault again, but nontheless, I am stumped.
=========================KERNEL.h
typedef long *LRESULT;
typedef long WPARAM;
typedef long LPARAM;
typedef struct tagHwnd {
long caption_msg;
} HWND;
typedef struct tagMsg {
HWND hwnd;
long msg;
WPARAM wParam;
LPARAM lParam;
long time;
} KM_MSG;
typedef LRESULT(*callBack)(HWND hwnd, long message, WPARAM w, LPARAM l);
LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam);
=========================KERNEL.c
#include <stdio.h>
#include "KERNEL.h"
callBack cb[1];
int main(void)
{
KM_MSG m; HWND hwnd;
hwnd.caption_msg = 1; m.msg = 1; m.lParam = 2; m.wParam = 3;
cb[0] = CALLBACK_WP_INTRO;
CALLBACK_WP_INTRO(hwnd, m.msg, m.wParam, m.lParam);
}
=========================WP_INTRO.h
// no code!
=========================WP_INTRO.c
#include "KERNEL.h"
LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam)
{
return 0;
}
==================================
LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam);
is included twice. The first time by KERNEL.c and the second time by the
#include "KERNEL.h"
Now, this compiles... no errors and no warnings.
//////////////////////////////////////////////////////////////
But now consider the following small program sample where the same prototype
function is still included twice.... still using the #include pre-proccesor
directives. however this time it generating errors ????
=========================KERNEL.h
typedef long *LRESULT;
typedef long WPARAM;
typedef long LPARAM;
typedef struct tagHwnd {
long caption_msg;
} HWND;
typedef struct tagMsg {
HWND hwnd;
long msg;
WPARAM wParam;
LPARAM lParam;
long time;
} KM_MSG;
typedef LRESULT(*callBack)(HWND hwnd, long message, WPARAM w, LPARAM l);
=========================KERNEL.c
#include <stdio.h>
#include "KERNEL.h"
#include "WP_INTRO.h"
callBack cb[1];
int main(void)
{
KM_MSG m; HWND hwnd;
hwnd.caption_msg = 1; m.msg = 1; m.lParam = 2; m.wParam = 3;
cb[0] = CALLBACK_WP_INTRO;
CALLBACK_WP_INTRO(hwnd, m.msg, m.wParam, m.lParam);
}
=========================WP_INTRO.h
LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam);
=========================WP_INTRO.c
#include "WP_INTRO.h"
#include "KERNEL.h"
LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam)
{
return 0;
}
====================================
LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam);
is also included twice. The first time by KERNEL.c with the following
#include "WP_INTRO.h"
#include "WP_INTRO.h"
1>c:\_dts_programming\pic\_microchip_issues\vc++\function_pointers\function_pointers\wp_intro.h(1)
: error C2061: syntax error : identifier 'CALLBACK_WP_INTRO'
1>c:\_dts_programming\pic\_microchip_issues\vc++\function_pointers\function_pointers\wp_intro.h(1) : error C2059: syntax error : ';'
1>c:\_dts_programming\pic\_microchip_issues\vc++\function_pointers\function_pointers\wp_intro.h(1)
: error C2146: syntax error : missing ')' before identifier 'hwnd'
1>c:\_dts_programming\pic\_microchip_issues\vc++\function_pointers\function_pointers\wp_intro.h(1) : error C2061: syntax error : identifier 'hwnd'
1>c:\_dts_programming\pic\_microchip_issues\vc++\function_pointers\function_pointers\wp_intro.h(1) : error C2059: syntax error : ','
1>c:\_dts_programming\pic\_microchip_issues\vc++\function_pointers\function_pointers\wp_intro.h(1) : error C2059: syntax error : ')'
The reason why I am trying to code it this way, is that I was trying to
include the function prototype in the correct header which belongs to the
respective .c file.
For example, *I think* all function prototypes should be declared in the
specific header which is included by a .c file which carries the function's
definitions.
All help appreciated!
**************SORRY, MY FAULT... I APOLOGIZE! I FIGURED IT OUT*************

I had to include KERNEL.h before WP_INTRO.h like this:

=========================WP_INTRO.c
#include "KERNEL.h"
#include "WP_INTRO.h"

Excuse this post!

Reagrds
Robert
Igor Tandetnik
2009-12-26 21:43:36 UTC
Permalink
Post by Robby
**************SORRY, MY FAULT... I APOLOGIZE! I FIGURED IT OUT*************
=========================WP_INTRO.c
#include "KERNEL.h"
#include "WP_INTRO.h"
The lesson here is: headers should be self-sufficient whenever possible. A header should forward-declare all symbols it uses, or else #include other headers it depends on. Then you can avoid this problem whereby headers only work when included in certain order. Imagine you have 10 headers, not two, some of which depend on others in non-obvious ways. Now try to figure out which order they must be included in to get them to compile.

A rule of thumb: each header (let's call it X.h) in your program should be written in such a way that a source file consisting of a single line

#include "X.h"

would compile successfully.


Once you start including some headers into other headers, you may run into another problem where the same header is indirectly included more than once into the same source. To help with this, use include guards:

http://en.wikipedia.org/wiki/Include_guard


Putting it all together, your example could be written this way:

=========================KERNEL.h
#ifndef KERNEL_H
#define KERNEL_H

typedef long *LRESULT;
typedef long WPARAM;
typedef long LPARAM;

typedef struct tagHwnd {
long caption_msg;
} HWND;

typedef struct tagMsg {
HWND hwnd;
long msg;
WPARAM wParam;
LPARAM lParam;
long time;
} KM_MSG;

typedef LRESULT(*callBack)(HWND hwnd, long message, WPARAM w, LPARAM l);

#endif /* KERNEL_H */

=========================WP_INTRO.h
#ifndef WP_INTRO_H
#define WP_INTRO_H

#include "KERNEL.h"

LRESULT CALLBACK_WP_INTRO(
HWND hwnd, long message, WPARAM wParam, LPARAM lParam);

#endif /* WP_INTRO_H */


Now your .c files can include headers they need in any order, without having to think of any dependencies between them.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not necessarily a good idea. It is hard to be sure where they are going to land, and it could be dangerous sitting under them as they fly overhead. -- RFC 1925
Robby
2009-12-28 06:13:01 UTC
Permalink
Post by Igor Tandetnik
Post by Robby
**************SORRY, MY FAULT... I APOLOGIZE! I FIGURED IT OUT*************
=========================WP_INTRO.c
#include "KERNEL.h"
#include "WP_INTRO.h"
The lesson here is: headers should be self-sufficient whenever possible. A header should forward-declare all symbols it uses, or else #include other headers it depends on. Then you can avoid this problem whereby headers only work when included in certain order. Imagine you have 10 headers, not two, some of which depend on others in non-obvious ways. Now try to figure out which order they must be included in to get them to compile.
A rule of thumb: each header (let's call it X.h) in your program should be written in such a way that a source file consisting of a single line
#include "X.h"
would compile successfully.
http://en.wikipedia.org/wiki/Include_guard
[snip]

So, showing also the .c files.... I could re-write it all like this:

=========================KERNEL.h (L1)
#ifndef KERNEL_H
#define KERNEL_H

typedef long *LRESULT;
typedef long WPARAM;
typedef long LPARAM;

typedef struct tagHwnd {
long caption_msg;
} HWND;

typedef struct tagMsg {
HWND hwnd;
long msg;
WPARAM wParam;
LPARAM lParam;
long time;
} KM_MSG;

typedef LRESULT(*callBack)(HWND hwnd, long message, WPARAM w, LPARAM l);

#endif /* KERNEL_H */

=========================KERNEL.c (L26)
#include <stdio.h>
#include "KERNEL.h"
#include "WP_INTRO.h"
callBack cb[1];

int main(void)
{
KM_MSG m; HWND hwnd;
hwnd.caption_msg = 1; m.msg = 1; m.lParam = 2; m.wParam = 3;
cb[0] = CALLBACK_WP_INTRO;
CALLBACK_WP_INTRO(hwnd, m.msg, m.wParam, m.lParam);
}
=========================WP_INTRO.h (L39)
#ifndef WP_INTRO_H
#define WP_INTRO_H

#include "KERNEL.h"

LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam);

#endif /* WP_INTRO_H */

=========================WP_INTRO.c (L51)
#include "KERNEL.h"
#include "WP_INTRO.h"

LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam)
{
return 0;
}
==================================== (L61)

Well, since we are on the subject Igor, I really appreciate that you have
brought this up, because I was always wondering what inclusion guards were
really used for and I would like to go through some things with you.

First, the KERNEL.c file will include the KERNEL.h file at line 28. In doing
so KERNEL_H is defined and all the contents of KERNEL.h are included in the
KERNEL.c file portion of the program. Therefore, from this point on, any
other .c file that tries to include KERNEL.h won't be able to due to the
inclusion guards we set up in KERNEL.h.

Next, The KERNEL.c file will include the WP_INTRO.h file at line 29. In
doing so, WP_INTRO_H is defined and all the contents of WP_INTRO.h are also
included in the in the KERNEL.c file portion of the program. But at this
point in WP_INTRO.h we also include KERNEL.h file again on line 43, but any
further inclusion of KERNEL.h is prevented since KERNEL_H is already defined.

Therefore, from this point on, any other .c file that tries to include
KERNEL.h or WP_INTRO.h won't be able to due to the inclusion guards we set up
in KERNEL.h and WP_INTRO.h.

Further down stream, when the compiler gets to the WP_INTRO.c file, it will
try to include KERNEL.h again at line 52 but won't be able to due to the
inclusion guards.

The problem is that WP_INTRO.c module absolutely needs to include the
KERNEL.h file to get its declarations such as HWND and so forth ... no?

And the same goes for when the compiler tries to include WP_INTRO.h at line
53 and still won't be able to include it because WP_INTRO_H is defined... so
then the following prototype declared in WP_INTRO.h:

LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam);

will never be included/seen by WP_INTRO.c.

I have not tried the above code yet, but just by looking at it, I don't
think it will compile since there will be inclusions missing???

I guess I am missing something.

Thanks for your help.
Please get back.

Robert
David Wilkinson
2009-12-28 13:37:39 UTC
Permalink
Post by Robby
=========================KERNEL.h (L1)
#ifndef KERNEL_H
#define KERNEL_H
typedef long *LRESULT;
typedef long WPARAM;
typedef long LPARAM;
typedef struct tagHwnd {
long caption_msg;
} HWND;
typedef struct tagMsg {
HWND hwnd;
long msg;
WPARAM wParam;
LPARAM lParam;
long time;
} KM_MSG;
typedef LRESULT(*callBack)(HWND hwnd, long message, WPARAM w, LPARAM l);
#endif /* KERNEL_H */
=========================KERNEL.c (L26)
#include <stdio.h>
#include "KERNEL.h"
#include "WP_INTRO.h"
callBack cb[1];
int main(void)
{
KM_MSG m; HWND hwnd;
hwnd.caption_msg = 1; m.msg = 1; m.lParam = 2; m.wParam = 3;
cb[0] = CALLBACK_WP_INTRO;
CALLBACK_WP_INTRO(hwnd, m.msg, m.wParam, m.lParam);
}
=========================WP_INTRO.h (L39)
#ifndef WP_INTRO_H
#define WP_INTRO_H
#include "KERNEL.h"
LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam);
#endif /* WP_INTRO_H */
=========================WP_INTRO.c (L51)
#include "KERNEL.h"
#include "WP_INTRO.h"
LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam)
{
return 0;
}
==================================== (L61)
Well, since we are on the subject Igor, I really appreciate that you have
brought this up, because I was always wondering what inclusion guards were
really used for and I would like to go through some things with you.
First, the KERNEL.c file will include the KERNEL.h file at line 28. In doing
so KERNEL_H is defined and all the contents of KERNEL.h are included in the
KERNEL.c file portion of the program. Therefore, from this point on, any
other .c file that tries to include KERNEL.h won't be able to due to the
inclusion guards we set up in KERNEL.h.
Next, The KERNEL.c file will include the WP_INTRO.h file at line 29. In
doing so, WP_INTRO_H is defined and all the contents of WP_INTRO.h are also
included in the in the KERNEL.c file portion of the program. But at this
point in WP_INTRO.h we also include KERNEL.h file again on line 43, but any
further inclusion of KERNEL.h is prevented since KERNEL_H is already defined.
Therefore, from this point on, any other .c file that tries to include
KERNEL.h or WP_INTRO.h won't be able to due to the inclusion guards we set up
in KERNEL.h and WP_INTRO.h.
Further down stream, when the compiler gets to the WP_INTRO.c file, it will
try to include KERNEL.h again at line 52 but won't be able to due to the
inclusion guards.
No. Each .c file is compiled separately. Include guards do not prevent you from
including a file once, only from including it multiple times.

In your code, WP_INTRO.h includes Kernel.h. Therefore it is not actually
necessary to include Kernel.h in Kernel.c and WP_INTRO.c, but the include guards
allow you to do this without error.
--
David Wilkinson
Visual C++ MVP
Barry Schwarz
2009-12-28 16:58:34 UTC
Permalink
On Mon, 28 Dec 2009 08:37:39 -0500, David Wilkinson
snip
Post by David Wilkinson
Post by Robby
Further down stream, when the compiler gets to the WP_INTRO.c file, it will
try to include KERNEL.h again at line 52 but won't be able to due to the
inclusion guards.
No. Each .c file is compiled separately. Include guards do not prevent you from
including a file once, only from including it multiple times.
It's amazing that he could type in all that code and not take the
extra 10 seconds to compile it and see that his assumptions were
incorrect.
--
Remove del for email
Robby
2009-12-28 18:35:01 UTC
Permalink
Hello David and Igor,

Okay I now understand the imporatance of inclusion guards.
In my particular example, the dilema appears to be in the two following
files in conjunction to KERNEL.h.

And this would protect WP_INTRO.c from including KERNEL.h twice... the first
time being at:

=========================WP_INTRO.c (L51)
#include "KERNEL.h" //<<<<< Included once here!

and the second time being at:

=========================WP_INTRO.h (L39)
#ifndef WP_INTRO_H
#define WP_INTRO_H

#include "KERNEL.h" //<<<<< Included the second time here! compiler error
here!

...
===================================

Having inclusion guards will protect us from the above scenario from
happening. But for now, in my project I don't have any headers that include
other headers. In the project that I am porting (from old compiler) the
KERNEL.c file includes all the header files once (and not to mention the
rediculous inclusions of all the other .c files also) and no other inclusions
were done anywhere else throughtout the whole project. So now I am porting at
a slow pace module by module and re-evaluating if I run into the header
incuding other headers scenario.

So now I am re-learning the right way. Here's what I learned from this post.

#1) Every .c file is compiled seperately and all header inclusions can only
include a particular header file once. (Which is very obvious to me now)

#2) Inclusion guards protect us from including the same header file twice
for the same .c file.

#3) Inclusion guards assure that even though we include the same header file
from:
a) a .c file (call it x.c) and,
b) a header file that is included by x.c
the result will be that the inclusion of that header file will never be
included more than once.

This all makes sence now...
Thanks Igor and David.... really appreciate it.

Sincere regards
Robert
Robby
2009-12-28 19:12:01 UTC
Permalink
Post by Robby
Hello David and Igor,
Okay I now understand the imporatance of inclusion guards.
In my particular example, the dilema appears to be in the two following
files in conjunction to KERNEL.h.
And this would protect WP_INTRO.c from including KERNEL.h twice... the first
=========================WP_INTRO.c (L51)
#include "KERNEL.h" //<<<<< Included once here!
=========================WP_INTRO.h (L39)
#ifndef WP_INTRO_H
#define WP_INTRO_H
#include "KERNEL.h" //<<<<< Included the second time here! compiler error
here!
...
===================================
Having inclusion guards will protect us from the above scenario from
happening. But for now, in my project I don't have any headers that include
other headers. In the project that I am porting (from old compiler) the
KERNEL.c file includes all the header files once (and not to mention the
rediculous inclusions of all the other .c files also) and no other inclusions
were done anywhere else throughtout the whole project. So now I am porting at
a slow pace module by module and re-evaluating if I run into the header
incuding other headers scenario.
Igor, Yup! looking at my sample, I think I should start using inclusion
guards if I will use your sample since I would code it this way:

=========================KERNEL.h (L1)
#ifndef KERNEL_H
#define KERNEL_H

typedef long *LRESULT;
typedef long WPARAM;
typedef long LPARAM;

typedef struct tagHwnd {
long caption_msg;
} HWND;

typedef struct tagMsg {
HWND hwnd;
long msg;
WPARAM wParam;
LPARAM lParam;
long time;
} KM_MSG;

typedef LRESULT(*callBack)(HWND hwnd, long message, WPARAM w, LPARAM l);

#endif /* KERNEL_H */

=========================KERNEL.c (L26)
#include <stdio.h>
#include "KERNEL.h"
#include "WP_INTRO.h"
callBack cb[1];

int main(void)
{
KM_MSG m; HWND hwnd;
hwnd.caption_msg = 1; m.msg = 1; m.lParam = 2; m.wParam = 3;
cb[0] = CALLBACK_WP_INTRO;
CALLBACK_WP_INTRO(hwnd, m.msg, m.wParam, m.lParam);
}
=========================WP_INTRO.h (L39)
#ifndef WP_INTRO_H
#define WP_INTRO_H

#include "KERNEL.h"

LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam);

#endif /* WP_INTRO_H */

=========================WP_INTRO.c (L51)
// #include "KERNEL.h" // <<<< Don't need this here!
#include "WP_INTRO.h"

LRESULT CALLBACK_WP_INTRO(HWND hwnd, long message, WPARAM wParam, LPARAM
lParam)
{
return 0;
}
==================================== (L61)

Thanks again!

Loading...