header files including other files

Sorry if this is out of place here. Comp.lang.C would probably be better but I left my flameproof underwear at work.

Really I guess I am asking advice about source code organisation.

I have a C langage project - a small robot. I want to use the various types defined in stdint.h such as uint8_t, uint16_t and so on as I expect the code to get ported to other processors.

Now, in any particular module, the module header file declares exported functions and variables and so needs to know the types. Is it considered acceptable to include the stdint.h header in the module header or is it better to include it in the source code. Now I have written it out loud, I suppose the latter is best as the header file never gets compiled, just included with other compilation units.

In a similar vein, the hardware definitions for the location of the buttons, LEDs, motor drivers etc all live in a single header file called hardware.h. In here, I have included the processor definitions header as the actual names of the ports and pins are closely dependent upon the actual processor used. This is the only place in the project where the processor header is included. Is it better to do this?

I would be grateful for anyone who can point me at a good resource recommeding how best to organize modules and their headers. From a lot of browsing about, everyone semms to just do their own thing but there must be good and bad practice out there to learn from.

Pete

Reply to
Peter Harrison
Loading thread data ...

I would include it in the module header, so that it isn't dependent on the order of #include directives in the source module. (I'm not sure what you mean by "the header file never gets compiled." If it doesn't, you don't need it.)

Your choice. I would probably do it the same way, for two reasons. First, it just makes sense to have this set of dependent information in its own module. Second, there may come a time when you want to include the same definitions in another module, or supply a different set of processor definitions in the hardware.h file.

Looking at my bookshelf, the only thing I remember is a chapter in Kernighan and Pike, "The Practice of Programming." I'm sure I have others at home, but it's too close to quitting time to thin about it .

IMO, this is a suitable topic for c.l.c. I don't think you'd get many flames.

--
Al Balmer
Sun City, AZ
Reply to
Al Balmer

If you want portability, stay away from those types. They are not required to be present on any system, but char, short, int, long are required. You can adjust the type you use by examining the values of _max and _min available in limits.h.

The most heavily used type should be int. Others are available when you need specific capabilities, or to save memory space, etc. int is generally arranged to have the fastest code associated, etc.

Cross-posted to c.l.c. with f'ups set.

--
 Chuck F (cbfalconer at maineline dot net)
   Available for consulting/temporary embedded and systems.
Reply to
CBFalconer

I have been considering this. What I would do, if your compiler doesn't include this, is to write my own and place in your source file collection.

#include /* use angle brackets */

Configure the compiler to search your files after the standard header directory. That way the compiler's version is included if it is defined, otherwise you get your own.

In your own version, protect your definitions with #if statements so that the definitions only occur on the relevant platform.

In my case, I will be compiling code for the 8-bit target and a PC. If I use uint_fast8_t for, say, indexes that are 8-bit maximum, I should get optimized code in each environment.

--
Thad
Reply to
Thad Smith

Unless you are doing something _very_ weird you should _always_ include predecessor header files in successor header files. Your header files should be designed so that you can plop one into an empty "C" file and compile it with no errors. Furthermore, they should be designed so that you can put them into a "C" file in any order and have a successful, predictable compile.

So the other thing you should do is guard the contents of your header file. So, for instance, at the start of header.h you should have

///////////////////////// // file: header.h // -- etc -- //

#ifndef HEADER_H #define HEADER_H

// (put your header stuff here)

#endif // HEADER_H

If you don't do this, then the second time the compiler encounters header.h (because you've included it everywhere) all hell will break loose.

--
Tim Wescott
Control systems and communications consulting
http://www.wescottdesign.com

Need to learn how to apply control theory in your embedded system?
"Applied Control Theory for Embedded Systems" by Tim Wescott
Elsevier/Newnes, http://www.wescottdesign.com/actfes/actfes.html
Reply to
Tim Wescott

With that in mind, I had already written my own stdint.h for the compiler I am using (Microchip C30) and, to take Thad's suggestion could try and ensure that the environment version got loaded if present. I figured that, for other compilers, tests in my own stdint.h for the compiler in use would allow a set of known-width types. This is partly about saving memory and trying to ensure I get eight bit quantities an minimum memory footprint. Wouldn't performing tests on limits.h leave me defining by own types anyway?

Reply to
Peter Harrison

I think standard practice is that header files should themselves include anything they need. Use include guards so that headers can be included more than once without error. E.g., for modules foo.c, the header file foo.h can be written:

/* foo.h header file */ #ifndef H_FOO #define H_FOO

/* ... */

#endif /*H_FOO */

Also foo.c should itself include foo.h so that mismatches are cought early by the compiler.

[...]
--

John Devereux
Reply to
John Devereux

... snip ...

You can only create types in C with struct or enums. Anything else is simply an alias, including those unint8_ts etc. If you want exactly 8 bits of something, put it in a type that can hold those 8 bits, and mask off anything outside them. You have the standard guarantees that char, short, int, long can hold at least 8, 16, 16,

32 bits respectively. Your choice as to un/signed versions, dependant on numeric range and overflow action desired. Remember that signed objects create undefined or system defined behaviour on overflow, while unsigned do modulo arithmetic, and are fully defined at all times (except division by zero).
--
 Chuck F (cbfalconer at maineline dot net)
   Available for consulting/temporary embedded and systems.
Reply to
CBFalconer

I'll offer the differing opinion here. In general we dislike and don't allow nested header files. They can be the proverbial can of worms.

I agree with Tim that you should always you include protection.

We require all code to be linted prior to release. No excuses, no exceptions.

Lint tends to be fussy about unused include files. Having a "standard set" of nested includes tends to get lots of lint hits.

It does require that the includes be ordered though. This requires some planning, but I am convinced it will help with portability.

As far as types go, we restrict usage of atomic types (int, char, etc.). Atomic types are often not very portable. I think the stdint set is a fine idea, but I would include it from the source file, not another header.

Scott

Reply to
Not Really Me

I didn't read all the replies closely, but who recommended that? A header should only include headers that it needs. I'm not even sure how I'd go about specifying a "standard" set of nested includes. It would mean that some include files deliberately include others that they don't need.

I have seen *programs* that includes a sort of standard selection of (non-nested) includes whether they were needed or not. Also, occasionally a program is eventually modified so that an include file is no longer needed. I find lint useful in finding those, and I usually change them.

--
Al Balmer
Sun City, AZ
Reply to
Al Balmer

I generally recommend that every source file be self-sufficient. If it needs anything supplied by some other header, it has to #include that header, period. One nice property of this rule is that it's trivially easy to test: every single C language file, _including_ the headers, must pass through Lint (or the compiler, if you don't have Lint) without errors.

Generally: yes. The "hardware.h" header only achieves its job if *all* access to the hardware goes through it. The only reason for any other module to directly include the vendor header would be to bypass "hardware.h". Not good.

Reply to
Hans-Bernhard Bröker

This is very concise and excellent advice. Thanks Tim.

--
Michael N. Moran           (h) 770 516 7918
5009 Old Field Ct.         (c) 678 521 5460
Kennesaw, GA, USA 30144    http://mnmoran.org

"So often times it happens, that we live our lives in chains
  and we never even know we have the key."
"Already Gone" by Jack Tempchin (recorded by The Eagles)

The Beatles were wrong: 1 & 1 & 1 is 1
Reply to
Michael N. Moran

How do you write only the masked bits to the device?

--
Al Balmer
Sun City, AZ
Reply to
Al Balmer

... snip ...

Investigate the i/o of the device.

--
 Chuck F (cbfalconer at maineline dot net)
   Available for consulting/temporary embedded and systems.
Reply to
CBFalconer

Point is that your advice may not always work.

There is good reason for using the stdint types, when they are available. They are supported by many compilers, not just fully C99 compliant ones.

--
Al Balmer
Sun City, AZ
Reply to
Al Balmer

Why not? The device input is done via things constructed from byte, short, int, long, float, double, etc. Not from unint8_t*.

--
 Chuck F (cbfalconer at maineline dot net)
   Available for consulting/temporary embedded and systems.
Reply to
CBFalconer

(I said output, btw, not input.) Then you don't need the mask. What the stdint types do is make porting to another architecture simple when there is a suitable type available. If there isn't, then masking another type might be useful.

--
Al Balmer
Sun City, AZ
Reply to
Al Balmer

I believe we are talking about the same thing. By 'device input' I mean input to the device. By investigate the i/o I mean that certain wires on certain ports connect to various device entities, and are described by the i/o protocol. I see no need to patch bits, in general.

--
 Chuck F (cbfalconer at maineline dot net)
   Available for consulting/temporary embedded and systems.
Reply to
CBFalconer

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.