newbie question about preprocessing

S

sieg1974

Hi,

I have made a program that is divided in many group of functions, and
each of these groups has its .h and .c files ( for example dutils.h
and dutils.c ). And to avoid the same .h file to be include more than
once, I wrote these command everywhere where I need to include
something.

#ifndef H_DUTILS
# define H_DUTILS
# include "dutils.h"
#endif

Is it a good way to do it, or there is a better way?

Thanks,

Andre
 
T

Tom Zych

sieg1974 said:
I have made a program that is divided in many group of functions, and
each of these groups has its .h and .c files ( for example dutils.h
and dutils.c ). And to avoid the same .h file to be include more than
once, I wrote these command everywhere where I need to include
something.
#ifndef H_DUTILS
# define H_DUTILS
# include "dutils.h"
#endif
Is it a good way to do it, or there is a better way?

A better way is to put the same kind of logic inside the header file
itself:

#ifndef DUTILS_H /* note changed macro name */
#define DUTILS_H
[the rest of the header file here]
#endif

Then you only need #include "dutils.h" in the other files.
 
R

Robert Stankowic

Tom Zych said:
A better way is to put the same kind of logic inside the header file
itself:

#ifndef DUTILS_H /* note changed macro name */

Why did you change it?
AFAIK macro-names starting with upper case 'E' are reserved, so prefixing
the macro-name with H_ puts you on the safe side.
#define DUTILS_H
[the rest of the header file here]
#endif

Then you only need #include "dutils.h" in the other files.

Robert
 
D

Darrell Grainger

Hi,

I have made a program that is divided in many group of functions, and
each of these groups has its .h and .c files ( for example dutils.h
and dutils.c ). And to avoid the same .h file to be include more than
once, I wrote these command everywhere where I need to include
something.

#ifndef H_DUTILS
# define H_DUTILS
# include "dutils.h"
#endif

Is it a good way to do it, or there is a better way?

This will work in some instances. It depends a little on your compiler.
There is nothing in the C standard that indicates this has to work.

Here is a scenario where this fails. I have a make file. Rather than
having a single command to compile everything at once I want to compile
each source file to an object file and then link them all together. In
case your are curious why, if I have 10,000 source files I don't want to
recompile all of them if I make a change to just one file.

If I have two files that #include the same header file, the make command
will compile the frst file, the compiler will see that this is the first
time we have included the header and #include it. When I compile the
second file, this is a new run of the compiler so the compiler will thikn
we are accessing the header file for the first time, again. When we link
the object files from file one and file two there will be trouble.

Bottom line, this might work for you but it depends on how your compiler
works. Something to note: what would happen if it works for your current
compiler but two years from now you realize you need to change your setup
and it stops working? That is, you switch to a system I just described.

--
darrell at cs dot toronto dot edu
or
main(){int j=1234;char t[]=":mad:abcdefghijklmnopqrstuvwxyz.\n",*i=
"iqgbgxmdbjlgdv.lksrqek.n";char *strchr(const char *,int);while(
*i){j+=strchr(t,*i++)-t;j%=sizeof t-1;putchar(t[j]);} return 0;}
 
S

sieg1974

Tom Zych said:
sieg1974 said:
I have made a program that is divided in many group of functions, and
each of these groups has its .h and .c files ( for example dutils.h
and dutils.c ). And to avoid the same .h file to be include more than
once, I wrote these command everywhere where I need to include
something.
#ifndef H_DUTILS
# define H_DUTILS
# include "dutils.h"
#endif
Is it a good way to do it, or there is a better way?

A better way is to put the same kind of logic inside the header file
itself:

#ifndef DUTILS_H /* note changed macro name */
#define DUTILS_H
[the rest of the header file here]
#endif

Then you only need #include "dutils.h" in the other files.

But what would happen if I had two or more .c files that would include
stdio.h for example? Does stdio.h have these ifndef, define, endif
inside it? Or will it just be included more than once?

Andre
 
M

Mike Wahler

sieg1974 said:
Tom Zych <[email protected]> wrote in message
sieg1974 said:
I have made a program that is divided in many group of functions, and
each of these groups has its .h and .c files ( for example dutils.h
and dutils.c ). And to avoid the same .h file to be include more than
once, I wrote these command everywhere where I need to include
something.
#ifndef H_DUTILS
# define H_DUTILS
# include "dutils.h"
#endif
Is it a good way to do it, or there is a better way?

A better way is to put the same kind of logic inside the header file
itself:

#ifndef DUTILS_H /* note changed macro name */
#define DUTILS_H
[the rest of the header file here]
#endif

Then you only need #include "dutils.h" in the other files.

But what would happen if I had two or more .c files that would include
stdio.h for example?

Then the text from the stdio header will be pasted into
each .c file. Note that this will create two separate
translation units. The header is not being #included
more than once.

What I think you might have meant to ask is what
happens if #include <stdio.h> appears more than
once in the same source file.

Answer:
If the implementation is compliant The Right Thing(tm)
will happen.
Does stdio.h have these ifndef, define, endif
inside it?

It might.
Or will it just be included more than once?

The standard only stipulates that #including
a standard header more than once has the
same effect as if #included only once (with
one exception, see below). How this is achieved
is up to the implementation, but using 'include
guards' is common.

C&V:
=============================================================
ISO/IEC 9899:1999 (E)

[...]

7.1.2 Standard headers

[...]

4 Standard headers may be included in any order; each may be
included more than once in a given scope, with no effect
different from being included only once, except that the
effect of including <assert.h> depends on the definition
of NDEBUG (see 7.2). If used, a header shall be included
outside of any external declaration or definition, and it
shall first be included before the first reference to any
of the functions or objects it declares, or to any of the
types or macros it defines. However, if an identifier is
declared or defined in more than one header, the second and
subsequent associated headers may be included after the
initial reference to the identifier. The program shall not
have any macros with names lexically identical to keywords
currently defined prior to the inclusion.
=============================================================

-Mike
 
A

Arthur J. O'Dwyer

This will work in some instances. It depends a little on your compiler.
There is nothing in the C standard that indicates this has to work.

While technically true, that is a vacuous statement. The *only*
implementation-dependent part of the above is the bit between the
quotes -- some file systems might not know what "dutils.h" is meant
to represent. In the context of c.l.c and hosted implementations,
I think we can assume the OP's compiler has a decent file system.

The above code does the following:

Check whether H_DUTILS is defined. This check will be false
initially, since the implementation is not allowed to define
H_DUTILS for itself.
If not, define H_DUTILS,
and then #include a certain header file.
Otherwise, do nothing.

This is perfectly well-defined (except for the bit in quotes, as
I mentioned), and will work on every C compiler in existence (as
well as every C compiler *not* in existence).

[Tangential: Someone else suggested #defining DUTILS_H instead.
That's harmless in this case, but stupid in general. Don't listen
to that person.]

Here is a scenario where this fails. I have a make file. Rather than
having a single command to compile everything at once I want to compile
each source file to an object file and then link them all together. In
case your are curious why, if I have 10,000 source files I don't want to
recompile all of them if I make a change to just one file.

Okay; so far that's all irrelevant. 'make' is off-topic here,
and the compiler doesn't care how it's invoked anyway. Make or
no make, it's all the same to it.
If I have two files that #include the same header file, the make command
will compile the frst file, the compiler will see that this is the first
time we have included the header and #include it. When I compile the
second file, this is a new run of the compiler so the compiler will thikn
we are accessing the header file for the first time, again.

Yes, of course. That's the way most operating systems work -- program
data is "forgotten" between runs of the same program.
When we link
the object files from file one and file two there will be trouble.

Why? What kind of trouble are you experiencing?


-Arthur,
sounds like a case of "Doctor, it hurts when I do this..."
 
T

Tom Zych

Arthur J. O'Dwyer said:
[Tangential: Someone else suggested #defining DUTILS_H instead.
That's harmless in this case, but stupid in general. Don't listen
to that person.]

Um, why?
 
T

Tom Zych

Why did you change it?
AFAIK macro-names starting with upper case 'E' are reserved, so prefixing
the macro-name with H_ puts you on the safe side.

I was going to say, that's how the standard headers on my system do
it, but checking, I see they actually do _STDIO_H and such. I want
to see why Arthur says it's stupid.
 
K

Kevin Easton

Tom Zych said:
I was going to say, that's how the standard headers on my system do
it, but checking, I see they actually do _STDIO_H and such. I want
to see why Arthur says it's stupid.

It's irrelevant anyway (you can't use names like _DUTILS_H yourself
either) - the implementation headers are allowed to do things that your
code isn't. The reason for this is to give the implmentation (compiler
and libraries) a namespace in which it can define identifiers or
keywords with whatever semantics it wants to / needs to.

- Kevin.
 
R

Robert Stankowic

Tom Zych said:
I was going to say, that's how the standard headers on my system do
it, but checking, I see they actually do _STDIO_H and such. I want
to see why Arthur says it's stupid.

Well, stupid is a hard word (Hi, Arthur, no offense intended :)).
Just something like
#ifndef H_DUTILS_H_INCLUDED /*note the H_*/ protects me from inadvertent
clashing with the implementations' namespace (uppercase E followed by
another uppercase letter in macro-names (among others) is reserved for the
implementation)
So the original makro-name was better than your correction.
 
T

Tom Zych

Robert said:
Well, stupid is a hard word (Hi, Arthur, no offense intended :)).
Just something like
#ifndef H_DUTILS_H_INCLUDED /*note the H_*/ protects me from inadvertent
clashing with the implementations' namespace (uppercase E followed by
another uppercase letter in macro-names (among others) is reserved for the
implementation)
So the original makro-name was better than your correction.

Oh, I was thinking "E_*", not "E*". Is that general, or just your
implementation? Don't recall hearing of that before.
 
A

Arthur J. O'Dwyer

Ditto. ;-)
Oh, I was thinking "E_*", not "E*". Is that general, or just your
implementation? Don't recall hearing of that before.

From N869:

7.26.3 Errors <errno.h>

[#1] Macros that begin with E and a digit or E and an
uppercase letter (possibly followed by any combination of
digits, letters, and underscore) may be added to the
declarations in the <errno.h> header.

Around the same section in N869, you can find the other reserved
identifiers in C99; as well as str*, mem*, is* and to*, they include
E*, PRI*, SCN*, LC_*, SIG*, int*_t, and wcs* [where the asterisk
represents various -- but not all -- combinations of characters].
The last of these is the only one, AFAIK, of which you really have to
beware; the rest are only reserved for use as macros #defined in certain
headers (so if you don't include the headers I think you're safe).

So the following code (in two files) will cause undefined behavior:


==foo.c==
#include <errno.h>
#include "evil.h"
...

==evil.h==
#ifndef EVIL_H
#define EVIL_H
...
#endif


but I believe it would be safe to write

==foo.c==
#include "evil.h"
#undef EVIL_H
#include <errno.h>
...

==evil.h==
#ifndef EVIL_H
#define EVIL_H
...
#endif

That's a little silly, and becomes implausible when
you're dealing with medium-sized projects. Much easier
to follow a consistent, safe rule from the start.

-Arthur
 
P

pete

Tom said:
I was going to say, that's how the standard headers on my system do
it, but checking, I see they actually do _STDIO_H and such. I want
to see why Arthur says it's stupid.

I think you're missing the point.
The way that the implementation does it,
is the way that you're *not* supposed to do it.

No implementation comes with:
#define H_FILENAME
 
K

Kevin Easton

Tom Zych said:
Oh, I was thinking "E_*", not "E*". Is that general, or just your
implementation? Don't recall hearing of that before.

In general. They're only reserved if you've included errno.h, but if
you're writing a general header file you can't be sure if any file that
includes it isn't also going to include errno.h. Quoting from N869:

7.26.3 Errors <errno.h>
Macros that begin with E and a digit or E and an uppercase letter
(possibly followed by any combination of digits, letters, and
underscore) may be added to the declarations in the <errno.h> header.

7.1.3 Reserved identifiers
1 Each header declares or defines all identifiers listed in its
associated subclause, and optionally declares or defines identifiers
listed in its associated future library directions subclause and
identifiers which are always reserved either for any use or for use as
file scope identifiers.

2 No other identifiers are reserved. If the program declares or defines
an identifier in a context in which it is reserved (other than as
allowed by 7.1.4), or defines a reserved identifier as a macro name,
the behavior is undefined.

- Kevin.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top