how do you normally structure your source code

Thread Starter

bug13

Joined Feb 13, 2012
1,809
Hi guys

I am keen to know how you structure your source code, so I can learn something from you guys and improve the way I do things.

So here was how I did it in the past:
Code:
/*!    There are all in the same folder
*    Say under /uart
*/

uart.h
uart.c
Here is how I do it now:
Code:
/*!    There are all in the same folder
*    Say under /uart
*/

uart_def.h            /* constant etc...                */
uart_types.h        /* typedef struct etc...        */
uart_api.h            /* external function prototype    */
uart_api.c            /* private function prototype,
                     * And both private the public
                     * functions body
                     */
                  
uart.h                /* application function prototype    */
uart.c                /* application function body        */
How do you guys structure you code, and what do you think I can improve on? Thanks guys!
 

MrChips

Joined Oct 2, 2009
20,329
I think that would require too many files. I would go the opposite route.

Instead of uart.h and uart.c I called it serial.h and serial.c.
This is because my STM32 has many UART and USART modules. They would all go into the same file.
 

Thread Starter

bug13

Joined Feb 13, 2012
1,809
I think that would require too many files. I would go the opposite route.

Instead of uart.h and uart.c I called it serial.h and serial.c.
This is because my STM32 has many UART and USART modules. They would all go into the same file.
I am just using UART as example, can be ADC or PWM etc...

If I put everything into uart.h and uart.c (or serial.h and serial.c), I find that the file will get too long. Do you just put the driver in your serial.h and serial.c only? Or do you put application function in serial.h and serial.c as well?
 

DickCappels

Joined Aug 21, 2008
6,198
Use the necessary include files for the hardware and special functions I want, then try to keep the entire rest of the project in one long file. I am lazy about switching among files while testing and revising.

After pulling in the include files there is initialization shortly thereafter is the main routine, and most of the work done by the main routine is done by subroutine calls. The interrupt stuff is toward the end of the file. Communication among routines is through flags and RAM locations or predetermined registers. Sometime is almost looks like Forth source but without passing parameters on a stack (miss that).
 

MrChips

Joined Oct 2, 2009
20,329
I have one very long main.c file.
You need to think the motivation for creating separate files. For me, that motivation is code reusability. I have many projects on the go. Hence I look at which modules I want to reuse without modification. All application specific defines go in constant.h that is included in all modules.
 

402DF855

Joined Feb 9, 2013
173
My views on h/c/cpp organization are a bit radical, so keep that in mind. I have exceptions to the following guidelines but generally adhere to them.

1. Reduce/eliminate header file coupling by having the C file only include its header and one everything.h

C:
// uart.c
#include "everything.h"
#include "uart.h"
// Try not to put any more includes here, rather put them in everything.h
2. No repeated file names. I worked on a project where there were 6 class.h files, all different.

3. Flatten the directory structure. In fact entertain the idea of putting all .C and all .H in the same directory.

4. Header files rarely if ever include other header files.

5. Use "#pragma once" at the start of header files rather than old style #ifndef followed by #define STDIO_H.

6. Don't declare functions static unless there is a specific reason to do so.
 

Thread Starter

bug13

Joined Feb 13, 2012
1,809
3. Flatten the directory structure. In fact entertain the idea of putting all .C and all .H in the same directory.
Why is that? I find that it's easier to organised files if I put all the relative source files in the same folder.

6. Don't declare functions static unless there is a specific reason to do so.
Local private functions is one of t he reason I am guessing?
 

402DF855

Joined Feb 9, 2013
173
Why is that? I find that it's easier to organised files if I put all the relative source files in the same folder.
I find the directory structure gets out of control; you might see one header file in its own directory. My advice is to err on the side of less directories.
Local private functions is one of t he reason I am guessing?
Nope. Rare instances of improved performance might be a reason. Static declarations impede debugging and testing. Your function might be "local private" in your app, but often I want to see them anyways for unit testing.
 

Thread Starter

bug13

Joined Feb 13, 2012
1,809
Static declarations impede debugging and testing. Your function might be "local private" in your app, but often I want to see them anyways for unit testing.
Arrrrhh, I see, good point!


4. Header files rarely if ever include other header files.
How about this, I find myself using uint8_t, uint16_t and uint32_t all the time in a structure define in my header file, how do you deal with that?
C:
/* foo_types.h */

/* have to include this, so I can use uint8_t etc... */
#include <stdint.h>     
                      
typedef struct FOO {
    uint8_t     count;
    uint16_t    data;
    uint32_t    data2;
}foo_t;
 
I'd say re-useability and readability. You really want to strive for both. You also want to group in a way that doesnl;t includes stuff that isn't related. e.g. arithmetic may or may not include the trancendental functions sin cos tan etc.

I wrote this "weird" FORTRAN program once. the way you could pass variables made it unique. So, if I passed an argument of 1 that needed one structure and an argument of 2 needed another.

Example wierdrness: They at least had a numeric type, unit number and function code,

1. Get config data
2. Put config data
3. Display on screen
4. Calibrate
5. Log data
6. Send e.g. Send Shutter 1 open
and a few others.

I had a FORTRAN file which was a "device driver" so to speak. Everything for that instrument was contained in that one file.

When you saved config info, you would kill the file and basically re-write it. So, you would just call in a certain order.

When you got configuration data, the module would be passed a get config data. It would read lines from the config file for all of the units of that type. When a line came back that was for another instrument, it would back up the file read pointer and return.

So, it was like really cool.
 

Picbuster

Joined Dec 2, 2013
990
Hi guys

I am keen to know how you structure your source code, so I can learn something from you guys and improve the way I do things.

So here was how I did it in the past:
Code:
/*!    There are all in the same folder
*    Say under /uart
*/

uart.h
uart.c
Here is how I do it now:
Code:
/*!    There are all in the same folder
*    Say under /uart
*/

uart_def.h            /* constant etc...                */
uart_types.h        /* typedef struct etc...        */
uart_api.h            /* external function prototype    */
uart_api.c            /* private function prototype,
                     * And both private the public
                     * functions body
                     */
                 
uart.h                /* application function prototype    */
uart.c                /* application function body        */
How do you guys structure you code, and what do you think I can improve on? Thanks guys!
Use same names as used in your hardware.
Do not use PORTFbits.RF2 if this is your Alive_Led
example:
In your schematic the wire connected to mpu pin RF2 should be called Alive_Led
In the xx.h file
#define Alive_Led PORTFbits.RF2 // alive led
in your program / each sec interrupt Alive_Led=!Alive_Led;


It's also wise to use structs. This will combine all things from one hardware part like a GSM

GSM.Power
GSM.Number
GSM.Signal_Strength
*
*

All things related to the beep generator are stuffed into Beep_Gen struct
Beep_Gen.Beep_Interval++;
if (Beep_Gen.Beep_Interval > Beep_Gen.Beep_Time)
{
Beep_Gen.Beep_Interval=0;

This will make your code readable without long comments needed and a direct link to the hardware.

Picbuster
 

Thread Starter

bug13

Joined Feb 13, 2012
1,809
I find this part to be crucial.

Use function and variable names that make sense not just to you but to the unknown programmer to come after you.
Use long names.
Use struct as much as possible and wherever possible.
Yes agree, but sometime I run out of names idea!
 

402DF855

Joined Feb 9, 2013
173
A couple pet peeves. Add meaningful comments to code, not this type:
C:
counter++; // increment counter
The pointer asterisk "belongs" to the identifier not the type.
C:
SERIAL_DEVICE* p;     //common but a bad idea
C:
SERIAL_DEVICE *p;     //correct way
 
Top