Including one C source file in another - witty or wicked ?

M

Morris Dovey

Nickolai said:
Can there be different useful conventions? Can i.e. keeping all function
definitions in a single file be justified?

There can be.

The method you described can be used, but I think you'll discover
that it's counter-productive and distracting because it shifts
the focus from efficient function and flow to source
construction.

From my own embedded experience, it's worth whatever it takes to
make both function and flow as obvious as possible, _especially_
in device drivers and ISRs.

Not wishing to give offense, but I'd be inclined to split the
difference between "witty" and "wicked" and call the fragmented
scheme "half-witted".
 
N

Nickolai Leschov

Hi,

I have a project for embedded system written in C language. It uses a
strange technique - there are some '.c' source files that contain code
fragments and are not meant for compiling by themselves, but instead are
included in the middle of the function in the middle of other source
files. Here's an artificial example:

// isr.c file
....
static void interrupt isr(void)
{
unsigned char i, temp;
#include "usart.c" // serial channel
#include "i2c.c" // I2C channel
....
// modbus.c file
if(RCIF)
{
RCIF=0;
temp = RCREG; // receive data byte
....
// i2c.c file
if(SSPIF)
{
SSPIF = 0;
....

I was taught that the convention of having each distinct module (as in C
we don't have classes) represented by a a .c file [1] helps to do
modular programming. This technique screws that convention.

At the very least, I think that those source files should not have the
'.c' extension to avoid confusion, as any programmer would expect that a
file with '.c' extension will contain valid source that should compile.

On the other hand, in this project this technique has its use: #include
directive adds portions of code to an ISR that add various functionality
to the application.

I'm not sure how should I rewrite the code in a clearer way. Should I?

[1] Also I was taught that the convention of having each module
represented by a pair of .c and .h files helps object-oriented approach,
as we separate the interface from implementation and always have a place
to look up the interface.
Can there be different useful conventions? Can i.e. keeping all function
definitions in a single file be justified?

Regards,
Nickolai Leschov
 
S

santosh

Nickolai said:
Hi,

I have a project for embedded system written in C language. It uses a
strange technique - there are some '.c' source files that contain code
fragments and are not meant for compiling by themselves, but instead
are included in the middle of the function in the middle of other
source files. Here's an artificial example:

// isr.c file
...
static void interrupt isr(void)
{
unsigned char i, temp;
#include "usart.c" // serial channel
#include "i2c.c" // I2C channel
...
// modbus.c file
if(RCIF)
{
RCIF=0;
temp = RCREG; // receive data byte
...
// i2c.c file
if(SSPIF)
{
SSPIF = 0;
...

This "technique" is sometimes used in low-level code to include some
firmware related binary data, usually as arrays.
I was taught that the convention of having each distinct module (as in
C we don't have classes) represented by a a .c file [1] helps to do
modular programming. This technique screws that convention.

Yes. But no technique is holy. Those files may contain declarations that
are so large that their inclusion in the parent file would make the
latter most cumbersome to read and edit. Since those declarations are
probably just binary data and may not often change, nor would be of
immediate relevance to the parent file's code, their inclusion in a
separate file is perhaps the best way.
At the very least, I think that those source files should not have the
'.c' extension to avoid confusion, as any programmer would expect that
a file with '.c' extension will contain valid source that should
compile.

You have a point. They *are* C code, but not independently compilable.
But they might have been given the .c extension so that other
programmers would not get even more confused.
On the other hand, in this project this technique has its use:
#include directive adds portions of code to an ISR that add various
functionality to the application.

I'm not sure how should I rewrite the code in a clearer way. Should I?

I don't know. Would it significantly ease maintenance? Do you forsee any
other advantage in a rewrite? Only you would know if it would be worth
the risk to tamper with working code, merely for aesthetic reasons.
[1] Also I was taught that the convention of having each module
represented by a pair of .c and .h files helps object-oriented
approach, as we separate the interface from implementation and always
have a place to look up the interface.
Can there be different useful conventions? Can i.e. keeping all
function definitions in a single file be justified?

I'm not sure that I understand your question here. Certainly, as you
say, public declarations are kept in header files while their
implementations are other private data would be in one or more .c
files. This allows for distributing your software without source.

It more difficult to say whether a single .c file should contain at most
only a single function with external linkage. This might be very common
(indeed required) in languages like Java, but in C it's more common to
find each .c file having the definitions for a closely related set of
functions. Think rather about how to split your project logically or
functionally, rather than dogmatically following any convention, unless
of course if your workplace rules dictate otherwise.
 
H

H. S. Lahman

Responding to Leschov...
Here's an artificial example:

// isr.c file
...
static void interrupt isr(void)
{
unsigned char i, temp;
#include "usart.c" // serial channel
#include "i2c.c" // I2C channel
...
// modbus.c file
if(RCIF)
{
RCIF=0;
temp = RCREG; // receive data byte
...
// i2c.c file
if(SSPIF)
{
SSPIF = 0;
...

There three separate issues here...

Localization of scope of the includes (i.e., including them in the body
of the .c code). There is no real gain to this because the compiler is
going to include the code statically whether the local block is actually
invoked at run time or not. In fact, it can lead to object bloat if the
same includes are inserted in different places. Since the actual
included code is only visible during run-time debugging or in an
Assembly listing, it really doesn't matter where one includes the file
with respect to readability of the host .c file. So the only
justification is...

Providing code fragments of executable statements (i.e., rather than
modular code blocks). Essentially one is using the compiler's lexical
replacement to insert executable statements without block structuring.
Circumventing the 3GL block structuring should be a warning flag in
itself. There is really no need for this because C already has a macro
facility that could easily have handled the examples. If the code to be
inserted is too large, then it should have been in a procedure to
promote modularity. If one wants to make decisions that are based on
local context, one can use C's #define in a conventional header.

[Being able to change the #define value *within* the .c file body is one
justification for localizing includes. But one doesn't need to include
the C statements to do that; just the #define definition. However, this
is not very robust for maintenance; changing #define values "on the fly"
is much like an assigned goto in FORTRAN. It modifies flow of control in
a way that is not visible to the reader of the .c body. So I would look
for ways to define the decisions in a more visible fashion (e.g.,
additional #defines to capture the particular context).]

Including a .c file rather than a .h file. Given that one is going to do
the second thing, it is probably a good idea to call attention to the
fact that one is not using the C language in a normal way. Using a .c
should raise a flag to the reader that something strange is going on.

Bottom line: IMO such a practice is just getting "cute" with lexical
replacement and should be avoided. Using a language feature in an
unusual way when there are existing language features one could use in a
normal fashion to do the same thing is usually not a good idea. It
increases the risk that a maintainer will be confused and insert defects
when making changes.



--
There is nothing wrong with me that could
not be cured by a capful of Drano.

H. S. Lahman
(e-mail address removed)
Pathfinder Solutions
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development". Email
(e-mail address removed) for your copy.
Pathfinder is hiring:
http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH
 
D

David Tiktin

I have a project for embedded system written in C language. It
uses a strange technique - there are some '.c' source files that
contain code fragments and are not meant for compiling by
themselves, but instead are included in the middle of the function
in the middle of other source files. Here's an artificial example:

[snip example code]

Ah, I see other people had the same idea ;-)
I was taught that the convention of having each distinct module
(as in C we don't have classes) represented by a a .c file [1]
helps to do modular programming. This technique screws that
convention.

Yes, it does, but it's just a convention. Reality sometimes
intervenes ;-)
At the very least, I think that those source files should not have
the '.c' extension to avoid confusion, as any programmer would
expect that a file with '.c' extension will contain valid source
that should compile.

If the code is C code, the proper extension is useful to allow smart
code editors to handle it properly.
On the other hand, in this project this technique has its use:
#include directive adds portions of code to an ISR that add
various functionality to the application.

I have used this technique, also in the type of low-level driver ISR
code shown in your example. The reason was this. Way back in DOS
days when the ISA bus was the standard, IRQs could not be shared by
devices. So if you had 2 of the same device installed in a machine,
each had to have a separate (but nearly identical) ISR. This is was
also a time of fairly limited compilers and slow machines, so
particularly in ISR code, efficiency was paramount. (Writing ISRs in
C instead of assembler was considered pretty radical. And no
function calls allowed. *Everything* inline.) The code base I work
on had to support up to 4 of the same device installed at the same
time which meant compiling 4 *almost* identical ISRs. We did not
want to repeat the code, so we tried to use macros, but the compilers
we used blew up on macros over a certain size, which these turned out
to be. What to do? So we had a base .c file that looked something
like this:

#define DEVICE 0
isr0()
{
#include "isrguts.c"
}

#define DEVICE 1
isr1()
{
#include "isrguts.c"
}

I doubt I would do it that way now, but basically, at the time, we
were working around the limitations of our tools.

Incidentally, each of our devices had 2 or more lines which again
required repetition of almost identical code. So inside isrguts.c
you'd likely see code like:

switch (line)
{
case 0;

#define LINE 0
#include "isrlineguts.c"
break;

case 1;

#define LINE 1
#include "isrlineguts.c"
break;
...
}

Oh, we were *bad*! Those were the days!

Dave
 
D

David Lightstone

Nickolai Leschov said:
Hi,

I have a project for embedded system written in C language. It uses a
strange technique - there are some '.c' source files that contain code
fragments and are not meant for compiling by themselves, but instead are
included in the middle of the function in the middle of other source
files. Here's an artificial example:

// isr.c file
...
static void interrupt isr(void)
{
unsigned char i, temp;
#include "usart.c" // serial channel
#include "i2c.c" // I2C channel
...
// modbus.c file
if(RCIF)
{ RCIF=0;
temp = RCREG; // receive data byte
...
// i2c.c file
if(SSPIF)
{
SSPIF = 0;
...

I was taught that the convention of having each distinct module (as in C
we don't have classes) represented by a a .c file [1] helps to do modular
programming. This technique screws that convention.


The presence of include files within a procedure as aestetically unpleasing

Back in 1995 I was involved in a project that would have been a failure if
we followed standard C coding conventions and avoided including c source
files. The linkage editor provided for the micro was to put things very,
very diplomatically somewhat deficient. (Switching development tools was not
an option. We were probably the only group in the world using the processor
at the time )

With the linkage editor being unpredictable, we had no choice but to force
the compilier to do as much of the work as possible. (ie a very, very small
number of object files to pass to the linkage editor.

We resolved the problem by modularizing the code, following the usual C
conventions, but rather than independently compile each file, we just
included them in a "linkage editor bypass" file. One source code file, 4
people developing code would have been a merge nightmare.

The alternative was to engage in a debug effort for the linkage editor.



At the very least, I think that those source files should not have the
'.c' extension to avoid confusion, as any programmer would expect that a
file with '.c' extension will contain valid source that should compile.

On the other hand, in this project this technique has its use: #include
directive adds portions of code to an ISR that add various functionality
to the application.

I'm not sure how should I rewrite the code in a clearer way. Should I?

[1] Also I was taught that the convention of having each module
represented by a pair of .c and .h files helps object-oriented approach,
as we separate the interface from implementation and always have a place
to look up the interface.
Can there be different useful conventions? Can i.e. keeping all function
definitions in a single file be justified?

Regards,
Nickolai Leschov
 
R

Robbie Hatley

"#include"ing one C file in another is a thing I used to do at the
last company I worked for. The reason there was, while we had lots
of program memory (flash memory), we had very little stack space
(we only had a few hundred bytes of RAM).

So instead of doing this:

int func1 (void)
{
...
func2();
...
}

int func2 (void)
{
...
}


What we would do instead was:

int func1 (void)
{
...
#include func2.c; // just insert code from func2 here
...
}

Why? To save a few more bytes of stack usage! Bloats the size of
the code in flash, but uses less RAM.

We used that and other weird tricks to get our firmware to
work right. Another cute trick was, we compiled certain parts
of the program to machine language, then wrote the opcodes for
the compiled instructions to an array, like so:

// in WriteStats.c:
int WriteStats [252] =
{
0xBC, 0x3A, 0x57, 0x3B, ...
};

(WriteStats.c was generated from the machine-language file
by a batch file which called a sed script which formatted
it.)

// in main.c:
int func1 (void)
{
...
#include "WriteStats.c"
...
}

func1 copied the contents of that array to RAM, then transfered
execution to the start of that array. The reason for this
was, this code handled writes to flash, and you can't write
to flash while executing from flash, so you have to transfer
control to RAM.

(If we'd been REAL programmers, we would have just written
the whole thing in machine language directly. But none of
us were quite up to that, so we cheated and used C and a
compiler.)
 
G

George Peter Staplin

Nickolai said:
Hi,

I have a project for embedded system written in C language. It uses a
strange technique - there are some '.c' source files that contain code
fragments and are not meant for compiling by themselves, but instead are
included in the middle of the function in the middle of other source
files. Here's an artificial example:

// isr.c file
...
static void interrupt isr(void)
{
unsigned char i, temp;
#include "usart.c" // serial channel
#include "i2c.c" // I2C channel
...
// modbus.c file
if(RCIF)
{
RCIF=0;
temp = RCREG; // receive data byte
...
// i2c.c file
if(SSPIF)
{
SSPIF = 0;
...

I was taught that the convention of having each distinct module (as in C
we don't have classes) represented by a a .c file [1] helps to do
modular programming. This technique screws that convention.

There could be a variety of reasons for doing that. usart.c could be
generated automatically for different builds. Perhaps it's a way to
eliminate #ifdefs.
At the very least, I think that those source files should not have the
'.c' extension to avoid confusion, as any programmer would expect that a
file with '.c' extension will contain valid source that should compile.

On the other hand, in this project this technique has its use: #include
directive adds portions of code to an ISR that add various functionality
to the application.

I'm not sure how should I rewrite the code in a clearer way. Should I?

If it helps you debug and fix the code faster, I suppose I would do
that, but first understand why it was written that way.
[1] Also I was taught that the convention of having each module
represented by a pair of .c and .h files helps object-oriented approach,
as we separate the interface from implementation and always have a place
to look up the interface.

Most of my .h files with function declarations are automatically
generated from a .csrcdb. A fancy editor ends up saving the .csrcdb
image. A program also generates the .c files from the .csrcdb.

So for a typical C program or shared library I have:
foo.csrcdb (generated by a graphical editing tool)
foo.h /* for data structures */
foo_compile.c
foo_proto.h (generated automatically)
foo.c (generated automatically)


So foo_compile.c is what gets compiled and it looks like:
#include "foo.h"
#include "foo_proto.h"
#include "foo.c"

Can there be different useful conventions? Can i.e. keeping all function
definitions in a single file be justified?

Performance is one reason why you might do this. Modern compilers like
GCC may reorder functions to optimize the instruction cache usage.

As I mentioned earlier, it could be used eliminate a lot of #ifdefery.

I personally use this method because it's the only way to do what I
want, within the constraints of the tools I use. The tools I use save
me time (especially with large projects), and make it easier to do
common things, so that's why I keep using them.


George
 
U

user923005

Hi,

I have a project for embedded system written in C language. It uses a
strange technique - there are some '.c' source files that contain code
fragments and are not meant for compiling by themselves, but instead are
included in the middle of the function in the middle of other source
files. Here's an artificial example:

// isr.c file
...
static void interrupt isr(void)
{
        unsigned char i, temp;
        #include "usart.c" // serial channel
        #include "i2c.c" // I2C channel
...
// modbus.c file
if(RCIF)
{      
        RCIF=0;
        temp = RCREG; // receive data byte
...
// i2c.c file
if(SSPIF)
{
        SSPIF = 0;
...

I was taught that the convention of having each distinct module (as in C
we don't have classes) represented by a a .c file [1] helps to do
modular programming. This technique screws that convention.

At the very least, I think that those source files should not have the
'.c' extension to avoid confusion, as any programmer would expect that a
file with '.c' extension will contain valid source that should compile.

On the other hand, in this project this technique has its use: #include
directive adds portions of code to an ISR that add various functionality
to the application.

I'm not sure how should I rewrite the code in a clearer way. Should I?

[1] Also I was taught that the convention of having each module
represented by a pair of .c and .h files helps object-oriented approach,
as we separate the interface from implementation and always have a place
to look up the interface.
Can there be different useful conventions? Can i.e. keeping all function
definitions in a single file be justified?

I do it sometimes when I want to get the last ounce of performance out
of something.
It allows most compilers to inline a little bit better.
But in general, it is a bad idea.
So I would classify it as witty and wicked.
 
M

MisterE

I'm not sure how should I rewrite the code in a clearer way. Should I?

On embedded systems you don't always want to call some function. The code
probably started out with each file as being a function that was called from
the main file. Maybe this was because the compiler can't optimize to make
them inline functions. This is especially important when dealing with ISRs
on embedded microprocessors, where the cost entering a subroutine takes a
significant amount of time. Some microcontrollers cannot enter a subroutine
when in an interrupt either. Especially if the interrupt sequence has been
optimised to only save certain registers tc. etc. etc.

If there is a reason, you would think it would be documented.
 
P

Phlip

MisterE said:
On embedded systems you don't always want to call some function. The
code probably started out with each file as being a function that was
called from the main file. Maybe this was because the compiler can't
optimize to make them inline functions. This is especially important
when dealing with ISRs on embedded microprocessors, where the cost
entering a subroutine takes a significant amount of time. Some
microcontrollers cannot enter a subroutine when in an interrupt either.
Especially if the interrupt sequence has been optimised to only save
certain registers tc. etc. etc.

That analysis only indicates macros, not more advanced preprocessor abuse!
 

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

Forum statistics

Threads
473,763
Messages
2,569,563
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top