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

Discussion in 'C Programming' started by Morris Dovey, Mar 5, 2008.

  1. Morris Dovey

    Morris Dovey Guest

    Nickolai Leschov wrote:

    > 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".

    --
    Morris Dovey
    DeSoto Solar
    DeSoto, Iowa USA
    http://www.iedu.com/DeSoto
     
    Morris Dovey, Mar 5, 2008
    #1
    1. Advertising

  2. 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
     
    Nickolai Leschov, Mar 5, 2008
    #2
    1. Advertising

  3. Morris Dovey

    santosh Guest

    Nickolai Leschov wrote:

    > 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.
     
    santosh, Mar 5, 2008
    #3
  4. Morris Dovey

    H. S. Lahman Guest

    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

    Pathfinder Solutions
    http://www.pathfindermda.com
    blog: http://pathfinderpeople.blogs.com/hslahman
    "Model-Based Translation: The Next Step in Agile Development". Email
    for your copy.
    Pathfinder is hiring:
    http://www.pathfindermda.com/about_us/careers_pos3.php.
    (888)OOA-PATH
     
    H. S. Lahman, Mar 5, 2008
    #4
  5. Morris Dovey

    David Tiktin Guest

    On 05 Mar 2008, Nickolai Leschov <> wrote:

    > 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.a.v.i.d T.i.k.t.i.n
    t.i.k.t.i.n [at] a.d.v.a.n.c.e.d.r.e.l.a.y [dot] c.o.m
     
    David Tiktin, Mar 5, 2008
    #5
  6. "Nickolai Leschov" <> wrote in message
    news:fqmaik$8vc$...
    > 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
     
    David Lightstone, Mar 5, 2008
    #6
  7. "#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.)

    --
    Cheers,
    Robbie Hatley
    lonewolf aatt well dott com
    www dott well dott com slant user slant lonewolf slant
     
    Robbie Hatley, Mar 5, 2008
    #7
  8. Nickolai Leschov wrote:
    > 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
     
    George Peter Staplin, Mar 6, 2008
    #8
  9. Morris Dovey

    user923005 Guest

    On Mar 5, 6:24 am, Nickolai Leschov <> wrote:
    > 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.
     
    user923005, Mar 6, 2008
    #9
  10. Morris Dovey

    MisterE Guest


    > 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.
     
    MisterE, Mar 7, 2008
    #10
  11. Morris Dovey

    Phlip Guest

    MisterE wrote:

    > 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!
     
    Phlip, Mar 8, 2008
    #11
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. vish
    Replies:
    2
    Views:
    1,732
    Steve C. Orr, MCSD
    Jul 16, 2003
  2. Tony Prichard
    Replies:
    0
    Views:
    736
    Tony Prichard
    Dec 12, 2003
  3. John A. Bailo

    Wicked Cool Java

    John A. Bailo, May 22, 2006, in forum: Java
    Replies:
    34
    Views:
    1,166
    Dale King
    May 26, 2006
  4. Johan
    Replies:
    20
    Views:
    1,606
    Arndt Jonasson
    Feb 27, 2007
  5. Neo Geshel
    Replies:
    36
    Views:
    341
    OmegaJunior
    Mar 18, 2007
Loading...

Share This Page