Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Post History

83%
+8 −0
Q&A C naming convention, module trigrams?

For what it's worth, I have some 20 years of experience designing embedded C systems, with large and small code bases both. Code design is some of the hardest things to do, since books about object...

posted 1y ago by Lundin‭  ·  edited 1y ago by Lundin‭

Answer
#5: Post edited by user avatar Lundin‭ · 2022-09-26T13:48:50Z (over 1 year ago)
  • For what it's worth, I have some 20 years of experience designing embedded C systems, with large and small code bases both. Code design is some of the hardest things to do, since books about object orientation (OO) etc only gets you so far - you have to learn what works out of experience.
  • Generally speaking, style and design matters become increasingly important when your code base grows. Code re-use and portability between projects is of course always nice too.
  • **Camel vs snake style**
  • Check out this interesting [research paper](http://www.cs.kent.edu/~jmaletic/papers/ICPC2010-CamelCaseUnderScoreClouds.pdf) regarding "CamelCase" vs "snake_case", which was carried out with eye tracking. Unsurprisingly they found that people used at reading one style or the other had it easier to read their preferred style. But also that when such bias was removed, camel case proved harder to read.
  • I have used all manner of styles over the years. I used to prefer camel at a time when I was doing a lot of PC programming, because it's more common there. Whereas snake is more common in embedded systems (and also in the *nix world). Generally I would say that when it comes to pure C (not C++), snake case code bases are more common.
  • Nowadays I solely use snake case and would recommend that if you have the option. Partially because of the above study, partially because it is more common in the code bases and protocol stacks etc you are likely to encounter when writing embedded C.
  • As for starting with lower/upper case using either style, that's still quite subjective and it's hard to argue for/against one or the other.
  • The most important thing of all though, is that you have a coding standard and that everyone follows it. It might be wise to separate _coding style_ (identifiers, indention, brace placement) from _coding guidelines_ (use this feature, don't use that feature). For example MISRA C mostly only covers the latter.
  • ---
  • **Identifier naming**
  • First of all please note that the C standard reserves a whole lot of identifiers. I won't go into this in detail since it's a big topic, but at least stay clear of all identifiers staring with an underscore, since they may collide with compiler libs.
  • Regarding constants and/or pre-processor macros, there is a wide consensus to use ALL_CAPS style for those. That's so common that I'd say it is an industry de facto standard, both in the PC world and the embedded world.
  • Regarding types, there's one very old but perhaps not necessarily common convention that types should be written starting with an upper case letter. I prefer to declare types with `_t` in the end instead, which is fine for embedded but not when coding POSIX.
  • Regarding identifiers for variables/functions: assuming you went with snake case, these should be lower case most of the time. _However_, in my experience, one thing that really helps making code manageable is to use _source module prefixes_.
  • That is, if you are writing a CAN driver, you have for example some `can.h` and `can.c`. You would then prefix all your functions with `CAN_` or `can_` and prefix all constants `CAN_`, documenting that these belong to the `can.h` driver. They need to _start_ the name with this, so you'd write `can_init` and _not_ `init_can`. It has to be a prefix so that the reader can quickly see which module a function belongs to.
  • In your code templates for headers, you could have something in the top like `Prefix: CAN`. For the coding standard I've developed at my current company, we use something like this on top of each header:
  • ```c
  • /*
  • <legal/copyright stuff here>
  • File can.h
  • Replaces old_can.h
  • Status Active
  • Conformance MISRA C:2012 // filled in after passing code review
  • Author John Doe
  • Created 2022-09-26
  • Prefix CAN
  • Description This is a HAL for CAN drivers-...
  • */
  • ```
  • Further down you'll have the documentation for each function together with the prototype format function declaration. In this case maybe something like `can_err_t can_init (void);`, assuming you have created a common result/error type (some enum) for all functions in the driver (another good idea).
  • One thing I would recommend to avoid, is to mix in vague terms like "handler", "driver" etc in the identifier name. It's rather superfluous and it's very hard to read code that calls `can_handler(); //handles CAN`... this literally tells the reader nothing other than "do not worry your pretty head". Better names are specific: `can_read_rxfifo`, `can_send` or whatever the function is actually doing.
  • ---
  • > I have propositions to start our names with a module trigram?
  • In general, for the love of obfuscation please never invent new TLA. Huh, what's a TLA? Yeah exactly that... _three letter abbreviations_. In your case `CAN` is a standardized and well-known one (Controller Area Network), so the reader is expected to understand what it means. That's fine, it's an established term. They do not however have a clue what `CDR` is supposed to mean... recordable compact disc? You should be using `CAN` in this case.
  • However, letters are cheap - they are in fact free. So not everything has to be an evil 3-letter abbreviation. Naming your relay driver with the prefix `relay_` rather than `rel_` is in fact far more readable, so go with that.
  • > actually, the majority of our codes don't really have modules, how to name a new function inside?
  • You should start using more disciple when designing then. Sure, there will be the application level top-tier and it may not need to have prefixes or be organized in modules. But everything else, particularly drivers, protocol handlers, specific algorithms - these should have their own module. This is correct design according to object orientation and other popular ways of designing programs. It reduces tight coupling (important!), it allows code re-usage and it reduces namespace collisions.
  • If I am to do a new project with CAN, I should just be able to grab your CAN driver, import it into the new project and be ready to go. Now if the CAN driver instead starts whining about some missing "relay module", then it was badly designed with tight coupling - it knows things about other modules that should be no business for a CAN driver, and consequently it also depends on other unrelated modules. That's a very bad state of affairs. The main problem is that tight coupling causes bugs to escalate through your whole program. Write a bug in the relay driver and suddenly the CAN driver stops working too.
  • Also consider using hardware abstraction layers (HAL). CAN is a perfect example of when this is useful. I have one HAL for CAN drivers (prefixed `CAN`) which I re-use across a whole lot of different microcontrollers. The HAL is the user interface but also dictates which functions each driver needs to implement. The user calls the HAL, ensures that the correct drivers are linked to the project, and then everything just works. You can then port the code to another MCU with a minimum of effort, assuming that the CAN driver for that system is already written and tested. When using HAL, the prefix belongs to the HAL and not to the underlying drivers, which probably have some more cryptic name taken from the specific CAN Controller (FlexCAN, bxCAN or whatever it might be called).
  • For what it's worth, I have some 20 years of experience designing embedded C systems, with large and small code bases both. Code design is some of the hardest things to do, since books about object orientation (OO) etc only gets you so far - you have to learn what works out of experience.
  • Generally speaking, style and design matters become increasingly important when your code base grows. Code re-use and portability between projects is of course always nice too.
  • **Camel vs snake style**
  • Check out this interesting [research paper](http://www.cs.kent.edu/~jmaletic/papers/ICPC2010-CamelCaseUnderScoreClouds.pdf) regarding "CamelCase" vs "snake_case", which was carried out with eye tracking. Unsurprisingly they found that people used at reading one style or the other had it easier to read their preferred style. But also that when such bias was removed, camel case proved harder to read.
  • I have used all manner of styles over the years. I used to prefer camel at a time when I was doing a lot of PC programming, because it's more common there. Whereas snake is more common in embedded systems (and also in the *nix world). Generally I would say that when it comes to pure C (not C++), snake case code bases are more common.
  • Nowadays I solely use snake case and would recommend that if you have the option. Partially because of the above study, partially because it is more common in the code bases and protocol stacks etc you are likely to encounter when writing embedded C.
  • As for starting with lower/upper case using either style, that's still quite subjective and it's hard to argue for/against one or the other.
  • The most important thing of all though, is that you have a coding standard and that everyone follows it. It might be wise to separate _coding style_ (identifiers, indention, brace placement) from _coding guidelines_ (use this feature, don't use that feature). For example MISRA C mostly only covers the latter.
  • ---
  • **Identifier naming**
  • First of all please note that the C standard reserves a whole lot of identifiers. I won't go into this in detail since it's a big topic, but at least stay clear of all identifiers staring with an underscore, since they may collide with compiler libs.
  • Regarding constants and/or pre-processor macros, there is a wide consensus to use ALL_CAPS style for those. That's so common that I'd say it is an industry de facto standard, both in the PC world and the embedded world.
  • Regarding types, there's one very old but perhaps not necessarily common convention that types should be written starting with an upper case letter. I prefer to declare types with `_t` in the end instead, which is fine for embedded but not when coding POSIX.
  • Regarding identifiers for variables/functions: assuming you went with snake case, these should be lower case most of the time. _However_, in my experience, one thing that really helps making code manageable is to use _source module prefixes_.
  • That is, if you are writing a CAN driver, you have for example some `can.h` and `can.c`. You would then prefix all your functions with `CAN_` or `can_` and prefix all constants `CAN_`, documenting that these belong to the `can.h` driver. They need to _start_ the name with this, so you'd write `can_init` and _not_ `init_can`. It has to be a prefix so that the reader can quickly see which module a function belongs to.
  • In your code templates for headers, you could have something in the top like `Prefix: CAN`. For the coding standard I've developed at my current company, we use something like this on top of each header:
  • ```c
  • /*
  • <legal/copyright stuff here>
  • File can.h
  • Replaces old_can.h
  • Status Active
  • Conformance MISRA C:2012 // filled in after passing code review
  • Author John Doe
  • Created 2022-09-26
  • Prefix CAN
  • Description This is a HAL for CAN drivers-...
  • */
  • ```
  • Further down you'll have the documentation for each function together with the prototype format function declaration. In this case maybe something like `can_err_t can_init (void);`, assuming you have created a common result/error type (some enum) for all functions in the driver (another good idea).
  • One thing I would recommend to avoid, is to mix in vague terms like "handler", "driver" etc in the identifier name. It's rather superfluous and it's very hard to read code that calls `can_handler(); //handles CAN`... this literally tells the reader nothing other than "do not worry your pretty head". Better names are specific: `can_read_rxfifo`, `can_send` or whatever the function is actually doing.
  • ---
  • > I have propositions to start our names with a module trigram?
  • In general, for the love of obfuscation please never invent new TLA. Huh, what's a TLA? Yeah exactly that... _three letter abbreviations_. In your case `CAN` is a standardized and well-known one (Controller Area Network), so the reader is expected to understand what it means. That's fine, it's an established term. They do not however have a clue what `CDR` is supposed to mean... recordable compact disc? You should be using `CAN` in this case.
  • However, letters are cheap - they are in fact free. So not everything has to be an evil 3-letter abbreviation. Naming your relay driver with the prefix `relay_` rather than `rel_` is in fact far more readable, so go with that.
  • > actually, the majority of our codes don't really have modules, how to name a new function inside?
  • You should start using more discipline when designing then. Sure, there will be the application level top-tier and it may not need to have prefixes or be organized in modules. But everything else, particularly drivers, protocol handlers, specific algorithms - these should have their own module. This is correct design according to object orientation and other popular ways of designing programs. It reduces tight coupling (important!), it allows code re-usage and it reduces namespace collisions.
  • If I am to do a new project with CAN, I should just be able to grab your CAN driver, import it into the new project and be ready to go. Now if the CAN driver instead starts whining about some missing "relay module", then it was badly designed with tight coupling - it knows things about other modules that should be no business for a CAN driver, and consequently it also depends on other unrelated modules. That's a very bad state of affairs. The main problem is that tight coupling causes bugs to escalate through your whole program. Write a bug in the relay driver and suddenly the CAN driver stops working too.
  • Also consider using hardware abstraction layers (HAL). CAN is a perfect example of when this is useful. I have one HAL for CAN drivers (prefixed `CAN`) which I re-use across a whole lot of different microcontrollers. The HAL is the user interface but also dictates which functions each driver needs to implement. The user calls the HAL, ensures that the correct drivers are linked to the project, and then everything just works. You can then port the code to another MCU with a minimum of effort, assuming that the CAN driver for that system is already written and tested. When using HAL, the prefix belongs to the HAL and not to the underlying drivers, which probably have some more cryptic name taken from the specific CAN Controller (FlexCAN, bxCAN or whatever it might be called).
#4: Post edited by user avatar Lundin‭ · 2022-09-26T08:57:17Z (over 1 year ago)
  • For what it's worth, I have some 20 years of experience designing embedded C systems, with large and small code bases both. Generally speaking, style and design matters become increasingly important when your code base grows. Code re-use and portability between projects is of course always nice too.
  • **Camel vs snake style**
  • Check out this interesting [research paper](http://www.cs.kent.edu/~jmaletic/papers/ICPC2010-CamelCaseUnderScoreClouds.pdf) regarding "CamelCase" vs "snake_case", which was carried out with eye tracking. Unsurprisingly they found that people used at reading one style or the other had it easier to read their preferred style. But also that when such bias was removed, camel case proved harder to read.
  • I have used all manner of styles over the years. I used to prefer camel at a time when I was doing a lot of PC programming, because it's more common there. Whereas snake is more common in embedded systems (and also in the *nix world). Generally I would say that when it comes to pure C (not C++), snake case code bases are more common.
  • Nowadays I solely use snake case and would recommend that if you have the option. Partially because of the above study, partially because it is more common in the code bases and protocol stacks etc you are likely to encounter when writing embedded C.
  • As for starting with lower/upper case using either style, that's still quite subjective and it's hard to argue for/against one or the other.
  • The most important thing of all though, is that you have a coding standard and that everyone follows it. It might be wise to separate _coding style_ (identifiers, indention, brace placement) from _coding guidelines_ (use this feature, don't use that feature). For example MISRA C mostly only covers the latter.
  • ---
  • **Identifier naming**
  • First of all please note that the C standard reserves a whole lot of identifiers. I won't go into this in detail since it's a big topic, but at least stay clear of all identifiers staring with an underscore, since they may collide with compiler libs.
  • Regarding constants and/or pre-processor macros, there is a wide consensus to use ALL_CAPS style for those. That's so common that I'd say it is an industry de facto standard, both in the PC world and the embedded world.
  • Regarding types, there's one very old but perhaps not necessarily common convention that types should be written starting with an upper case letter. I prefer to declare types with `_t` in the end instead, which is fine for embedded but not when coding POSIX.
  • Regarding identifiers for variables/functions: assuming you went with snake case, these should be lower case most of the time. _However_, in my experience, one thing that really helps making code manageable is to use _source module prefixes_.
  • That is, if you are writing a CAN driver, you have for example some `can.h` and `can.c`. You would then prefix all your functions with `CAN_` or `can_` and prefix all constants `CAN_`, documenting that these belong to the `can.h` driver. They need to _start_ the name with this, so you'd write `can_init` and _not_ `init_can`. It has to be a prefix so that the reader can quickly see which module a function belongs to.
  • In your code templates for headers, you could have something in the top like `Prefix: CAN`. For the coding standard I've developed at my current company, we use something like this on top of each header:
  • ```c
  • /*
  • <legal/copyright stuff here>
  • File can.h
  • Replaces old_can.h
  • Status Active
  • Conformance MISRA C:2012 // filled in after passing code review
  • Author John Doe
  • Created 2022-09-26
  • Prefix CAN
  • Description This is a HAL for CAN drivers-...
  • */
  • ```
  • Further down you'll have the documentation for each function together with the prototype format function declaration. In this case maybe something like `can_err_t can_init (void);`, assuming you have created a common result/error type (some enum) for all functions in the driver (another good idea).
  • One thing I would recommend to avoid, is to mix in vague terms like "handler", "driver" etc in the identifier name. It's rather superfluous and it's very hard to read code that calls `can_handler(); //handles CAN`... this literally tells the reader nothing other than "do not worry your pretty head". Better names are specific: `can_read_rxfifo`, `can_send` or whatever the function is actually doing.
  • ---
  • > I have propositions to start our names with a module trigram?
  • In general, for the love of obfuscation please never invent new TLA. Huh, what's a TLA? Yeah exactly that... _three letter abbreviations_. In your case `CAN` is a standardized and well-known one (Controller Area Network), so the reader is expected to understand what it means. That's fine, it's an established term. They do not however have a clue what `CDR` is supposed to mean... recordable compact disc? You should be using `CAN` in this case.
  • However, letters are cheap - they are in fact free. So not everything has to be an evil 3-letter abbreviation. Naming your relay driver with the prefix `relay_` rather than `rel_` is in fact far more readable, so go with that.
  • > actually, the majority of our codes don't really have modules, how to name a new function inside?
  • You should start using more disciple when designing then. Sure, there will be the application level top-tier and it may not need to have prefixes or be organized in modules. But everything else, particularly drivers, protocol handlers, specific algorithms - these should have their own module. This is correct design according to object orientation and other popular ways of designing programs. It reduces tight coupling (important!), it allows code re-usage and it reduces namespace collisions.
  • If I am to do a new project with CAN, I should just be able to grab your CAN driver, import it into the new project and be ready to go. Now if the CAN driver instead starts whining about some missing "relay module", then it was badly designed with tight coupling - it knows things about other modules that should be no business for a CAN driver, and consequently it also depends on other unrelated modules. That's a very bad state of affairs. The main problem is that tight coupling causes bugs to escalate through your whole program. Write a bug in the relay driver and suddenly the CAN driver stops working too.
  • Also consider using hardware abstraction layers (HAL). CAN is a perfect example of when this is useful. I have one HAL for CAN drivers (prefixed `CAN`) which I re-use across a whole lot of different microcontrollers. The HAL is the user interface but also dictates which functions each driver needs to implement. The user calls the HAL, ensures that the correct drivers are linked to the project, and then everything just works. You can then port the code to another MCU with a minimum of effort, assuming that the CAN driver for that system is already written and tested. When using HAL, the prefix belongs to the HAL and not to the underlying drivers, which probably have some more cryptic name taken from the specific CAN Controller (FlexCAN, bxCAN or whatever it might be called).
  • For what it's worth, I have some 20 years of experience designing embedded C systems, with large and small code bases both. Code design is some of the hardest things to do, since books about object orientation (OO) etc only gets you so far - you have to learn what works out of experience.
  • Generally speaking, style and design matters become increasingly important when your code base grows. Code re-use and portability between projects is of course always nice too.
  • **Camel vs snake style**
  • Check out this interesting [research paper](http://www.cs.kent.edu/~jmaletic/papers/ICPC2010-CamelCaseUnderScoreClouds.pdf) regarding "CamelCase" vs "snake_case", which was carried out with eye tracking. Unsurprisingly they found that people used at reading one style or the other had it easier to read their preferred style. But also that when such bias was removed, camel case proved harder to read.
  • I have used all manner of styles over the years. I used to prefer camel at a time when I was doing a lot of PC programming, because it's more common there. Whereas snake is more common in embedded systems (and also in the *nix world). Generally I would say that when it comes to pure C (not C++), snake case code bases are more common.
  • Nowadays I solely use snake case and would recommend that if you have the option. Partially because of the above study, partially because it is more common in the code bases and protocol stacks etc you are likely to encounter when writing embedded C.
  • As for starting with lower/upper case using either style, that's still quite subjective and it's hard to argue for/against one or the other.
  • The most important thing of all though, is that you have a coding standard and that everyone follows it. It might be wise to separate _coding style_ (identifiers, indention, brace placement) from _coding guidelines_ (use this feature, don't use that feature). For example MISRA C mostly only covers the latter.
  • ---
  • **Identifier naming**
  • First of all please note that the C standard reserves a whole lot of identifiers. I won't go into this in detail since it's a big topic, but at least stay clear of all identifiers staring with an underscore, since they may collide with compiler libs.
  • Regarding constants and/or pre-processor macros, there is a wide consensus to use ALL_CAPS style for those. That's so common that I'd say it is an industry de facto standard, both in the PC world and the embedded world.
  • Regarding types, there's one very old but perhaps not necessarily common convention that types should be written starting with an upper case letter. I prefer to declare types with `_t` in the end instead, which is fine for embedded but not when coding POSIX.
  • Regarding identifiers for variables/functions: assuming you went with snake case, these should be lower case most of the time. _However_, in my experience, one thing that really helps making code manageable is to use _source module prefixes_.
  • That is, if you are writing a CAN driver, you have for example some `can.h` and `can.c`. You would then prefix all your functions with `CAN_` or `can_` and prefix all constants `CAN_`, documenting that these belong to the `can.h` driver. They need to _start_ the name with this, so you'd write `can_init` and _not_ `init_can`. It has to be a prefix so that the reader can quickly see which module a function belongs to.
  • In your code templates for headers, you could have something in the top like `Prefix: CAN`. For the coding standard I've developed at my current company, we use something like this on top of each header:
  • ```c
  • /*
  • <legal/copyright stuff here>
  • File can.h
  • Replaces old_can.h
  • Status Active
  • Conformance MISRA C:2012 // filled in after passing code review
  • Author John Doe
  • Created 2022-09-26
  • Prefix CAN
  • Description This is a HAL for CAN drivers-...
  • */
  • ```
  • Further down you'll have the documentation for each function together with the prototype format function declaration. In this case maybe something like `can_err_t can_init (void);`, assuming you have created a common result/error type (some enum) for all functions in the driver (another good idea).
  • One thing I would recommend to avoid, is to mix in vague terms like "handler", "driver" etc in the identifier name. It's rather superfluous and it's very hard to read code that calls `can_handler(); //handles CAN`... this literally tells the reader nothing other than "do not worry your pretty head". Better names are specific: `can_read_rxfifo`, `can_send` or whatever the function is actually doing.
  • ---
  • > I have propositions to start our names with a module trigram?
  • In general, for the love of obfuscation please never invent new TLA. Huh, what's a TLA? Yeah exactly that... _three letter abbreviations_. In your case `CAN` is a standardized and well-known one (Controller Area Network), so the reader is expected to understand what it means. That's fine, it's an established term. They do not however have a clue what `CDR` is supposed to mean... recordable compact disc? You should be using `CAN` in this case.
  • However, letters are cheap - they are in fact free. So not everything has to be an evil 3-letter abbreviation. Naming your relay driver with the prefix `relay_` rather than `rel_` is in fact far more readable, so go with that.
  • > actually, the majority of our codes don't really have modules, how to name a new function inside?
  • You should start using more disciple when designing then. Sure, there will be the application level top-tier and it may not need to have prefixes or be organized in modules. But everything else, particularly drivers, protocol handlers, specific algorithms - these should have their own module. This is correct design according to object orientation and other popular ways of designing programs. It reduces tight coupling (important!), it allows code re-usage and it reduces namespace collisions.
  • If I am to do a new project with CAN, I should just be able to grab your CAN driver, import it into the new project and be ready to go. Now if the CAN driver instead starts whining about some missing "relay module", then it was badly designed with tight coupling - it knows things about other modules that should be no business for a CAN driver, and consequently it also depends on other unrelated modules. That's a very bad state of affairs. The main problem is that tight coupling causes bugs to escalate through your whole program. Write a bug in the relay driver and suddenly the CAN driver stops working too.
  • Also consider using hardware abstraction layers (HAL). CAN is a perfect example of when this is useful. I have one HAL for CAN drivers (prefixed `CAN`) which I re-use across a whole lot of different microcontrollers. The HAL is the user interface but also dictates which functions each driver needs to implement. The user calls the HAL, ensures that the correct drivers are linked to the project, and then everything just works. You can then port the code to another MCU with a minimum of effort, assuming that the CAN driver for that system is already written and tested. When using HAL, the prefix belongs to the HAL and not to the underlying drivers, which probably have some more cryptic name taken from the specific CAN Controller (FlexCAN, bxCAN or whatever it might be called).
#3: Post edited by user avatar Lundin‭ · 2022-09-26T08:55:48Z (over 1 year ago)
  • For what it's worth, I have some 20 years of experience designing embedded C systems, with large and small code bases both. Generally speaking, style and design matters become increasingly important when your code base grows. Code re-use and portability between projects is of course always nice too.
  • **Camel vs snake style**
  • Check out this interesting [research paper](http://www.cs.kent.edu/~jmaletic/papers/ICPC2010-CamelCaseUnderScoreClouds.pdf) regarding "CamelCase" vs "snake_case", which was carried out with eye tracking. Unsurprisingly they found that people used at reading one style or the other had it easier to read their preferred style. But also that when such bias was removed, camel case proved harder to read.
  • I have used all manner of styles over the years. I used to prefer camel at a time when I was doing a lot of PC programming, because it's more common there. Whereas snake is more common in embedded systems (and also in the *nix world). Generally I would say that when it comes to pure C (not C++), snake case code bases are more common.
  • Nowadays I solely use snake case and would recommend that if you have the option. Partially because of the above study, partially because it is more common in the code bases and protocol stacks etc you are likely to encounter when writing embedded C.
  • As for starting with lower/upper case using either style, that's still quite subjective and it's hard to argue for/against one or the other.
  • The most important thing of all though, is that you have a coding standard and that everyone follows it. It might be wise to separate _coding style_ (identifiers, indention, brace placement) from _coding guidelines_ (use this feature, don't use that feature). For example MISRA C mostly only covers the latter.
  • ---
  • **Identifier naming**
  • First of all please note that the C standard reserves a whole lot of identifiers. I won't go into this in detail since it's a big topic, but at least stay clear of all identifiers staring with an underscore, since they may collide with compiler libs.
  • Regarding constants and/or pre-processor macros, there is a wide consensus to use ALL_CAPS style for those. That's so common that I'd say it is an industry de facto standard, both in the PC world and the embedded world.
  • Regarding types, there's one very old but perhaps not necessarily common convention that types should be written starting with an upper case letter. I prefer to declare types with `_t` in the end instead, which is fine for embedded but not when coding POSIX.
  • Regarding identifiers for variables/functions: assuming you went with snake case, these should be lower case most of the time. _However_, I have long experience from designing and managing large embedded C code bases and one thing that really helps making code manageable is to use _source module prefixes_.
  • That is, if you are writing a CAN driver, you have for example some `can.h` and `can.c`. You would then prefix all your functions with `CAN_` or `can_` and prefix all constants `CAN_`, documenting that these belong to the `can.h` driver. They need to _start_ the name with this, so you'd write `can_init` and _not_ `init_can`. It has to be a prefix so that the reader can quickly see which module a function belongs to.
  • In your code templates for headers, you could have something in the top like `Prefix: CAN`. For the coding standard I've developed at my current company, we use something like this on top of each header:
  • ```c
  • /*
  • <legal/copyright stuff here>
  • File can.h
  • Replaces old_can.h
  • Status Active
  • Conformance MISRA C:2012 // filled in after passing code review
  • Author John Doe
  • Created 2022-09-26
  • Prefix CAN
  • Description This is a HAL for CAN drivers-...
  • */
  • ```
  • Further down you'll have the documentation for each function together with the prototype format function declaration. In this case maybe something like `can_err_t can_init (void);`, assuming you have created a common result/error type (some enum) for all functions in the driver (another good idea).
  • One thing I would recommend to avoid, is to mix in vague terms like "handler", "driver" etc in the identifier name. It's rather superfluous and it's very hard to read code that calls `can_handler(); //handles CAN`... this literally tells the reader nothing other than "do not worry your pretty head". Better names are specific: `can_read_rxfifo`, `can_send` or whatever the function is actually doing.
  • ---
  • > I have propositions to start our names with a module trigram?
  • In general, for the love of obfuscation please never invent new TLA. Huh, what's a TLA? Yeah exactly that... _three letter abbreviations_. In your case `CAN` is a standardized and well-known one (Controller Area Network), so the reader is expected to understand what it means. That's fine, it's an established term. They do not however have a clue what `CDR` is supposed to mean... recordable compact disc? You should be using `CAN` in this case.
  • However, letters are cheap - they are in fact free. So not everything has to be an evil 3-letter abbreviation. Naming your relay driver with the prefix `relay_` rather than `rel_` is in fact far more readable, so go with that.
  • > actually, the majority of our codes don't really have modules, how to name a new function inside?
  • You should start using more disciple when designing then. Sure, there will be the application level top-tier and it may not need to have prefixes or be organized in modules. But everything else, particularly drivers, protocol handlers, specific algorithms - these should have their own module. This is correct design according to object orientation and other popular ways of designing programs. It reduces tight coupling (important!), it allows code re-usage and it reduces namespace collisions.
  • If I am to do a new project with CAN, I should just be able to grab your CAN driver, import it into the new project and be ready to go. Now if the CAN driver instead starts whining about some missing "relay module", then it was badly designed with tight coupling - it knows things about other modules that should be no business for a CAN driver, and consequently it also depends on other unrelated modules. That's a very bad state of affairs. The main problem is that tight coupling causes bugs to escalate through your whole program. Write a bug in the relay driver and suddenly the CAN driver stops working too.
  • Also consider using hardware abstraction layers (HAL). CAN is a perfect example of when this is useful. I have one HAL for CAN drivers (prefixed `CAN`) which I re-use across a whole lot of different microcontrollers. The HAL is the user interface but also dictates which functions each driver needs to implement. The user calls the HAL, ensures that the correct drivers are linked to the project, and then everything just works. You can then port the code to another MCU with a minimum of effort, assuming that the CAN driver for that system is already written and tested. When using HAL, the prefix belongs to the HAL and not to the underlying drivers, which probably have some more cryptic name taken from the specific CAN Controller (FlexCAN, bxCAN or whatever it might be called).
  • For what it's worth, I have some 20 years of experience designing embedded C systems, with large and small code bases both. Generally speaking, style and design matters become increasingly important when your code base grows. Code re-use and portability between projects is of course always nice too.
  • **Camel vs snake style**
  • Check out this interesting [research paper](http://www.cs.kent.edu/~jmaletic/papers/ICPC2010-CamelCaseUnderScoreClouds.pdf) regarding "CamelCase" vs "snake_case", which was carried out with eye tracking. Unsurprisingly they found that people used at reading one style or the other had it easier to read their preferred style. But also that when such bias was removed, camel case proved harder to read.
  • I have used all manner of styles over the years. I used to prefer camel at a time when I was doing a lot of PC programming, because it's more common there. Whereas snake is more common in embedded systems (and also in the *nix world). Generally I would say that when it comes to pure C (not C++), snake case code bases are more common.
  • Nowadays I solely use snake case and would recommend that if you have the option. Partially because of the above study, partially because it is more common in the code bases and protocol stacks etc you are likely to encounter when writing embedded C.
  • As for starting with lower/upper case using either style, that's still quite subjective and it's hard to argue for/against one or the other.
  • The most important thing of all though, is that you have a coding standard and that everyone follows it. It might be wise to separate _coding style_ (identifiers, indention, brace placement) from _coding guidelines_ (use this feature, don't use that feature). For example MISRA C mostly only covers the latter.
  • ---
  • **Identifier naming**
  • First of all please note that the C standard reserves a whole lot of identifiers. I won't go into this in detail since it's a big topic, but at least stay clear of all identifiers staring with an underscore, since they may collide with compiler libs.
  • Regarding constants and/or pre-processor macros, there is a wide consensus to use ALL_CAPS style for those. That's so common that I'd say it is an industry de facto standard, both in the PC world and the embedded world.
  • Regarding types, there's one very old but perhaps not necessarily common convention that types should be written starting with an upper case letter. I prefer to declare types with `_t` in the end instead, which is fine for embedded but not when coding POSIX.
  • Regarding identifiers for variables/functions: assuming you went with snake case, these should be lower case most of the time. _However_, in my experience, one thing that really helps making code manageable is to use _source module prefixes_.
  • That is, if you are writing a CAN driver, you have for example some `can.h` and `can.c`. You would then prefix all your functions with `CAN_` or `can_` and prefix all constants `CAN_`, documenting that these belong to the `can.h` driver. They need to _start_ the name with this, so you'd write `can_init` and _not_ `init_can`. It has to be a prefix so that the reader can quickly see which module a function belongs to.
  • In your code templates for headers, you could have something in the top like `Prefix: CAN`. For the coding standard I've developed at my current company, we use something like this on top of each header:
  • ```c
  • /*
  • <legal/copyright stuff here>
  • File can.h
  • Replaces old_can.h
  • Status Active
  • Conformance MISRA C:2012 // filled in after passing code review
  • Author John Doe
  • Created 2022-09-26
  • Prefix CAN
  • Description This is a HAL for CAN drivers-...
  • */
  • ```
  • Further down you'll have the documentation for each function together with the prototype format function declaration. In this case maybe something like `can_err_t can_init (void);`, assuming you have created a common result/error type (some enum) for all functions in the driver (another good idea).
  • One thing I would recommend to avoid, is to mix in vague terms like "handler", "driver" etc in the identifier name. It's rather superfluous and it's very hard to read code that calls `can_handler(); //handles CAN`... this literally tells the reader nothing other than "do not worry your pretty head". Better names are specific: `can_read_rxfifo`, `can_send` or whatever the function is actually doing.
  • ---
  • > I have propositions to start our names with a module trigram?
  • In general, for the love of obfuscation please never invent new TLA. Huh, what's a TLA? Yeah exactly that... _three letter abbreviations_. In your case `CAN` is a standardized and well-known one (Controller Area Network), so the reader is expected to understand what it means. That's fine, it's an established term. They do not however have a clue what `CDR` is supposed to mean... recordable compact disc? You should be using `CAN` in this case.
  • However, letters are cheap - they are in fact free. So not everything has to be an evil 3-letter abbreviation. Naming your relay driver with the prefix `relay_` rather than `rel_` is in fact far more readable, so go with that.
  • > actually, the majority of our codes don't really have modules, how to name a new function inside?
  • You should start using more disciple when designing then. Sure, there will be the application level top-tier and it may not need to have prefixes or be organized in modules. But everything else, particularly drivers, protocol handlers, specific algorithms - these should have their own module. This is correct design according to object orientation and other popular ways of designing programs. It reduces tight coupling (important!), it allows code re-usage and it reduces namespace collisions.
  • If I am to do a new project with CAN, I should just be able to grab your CAN driver, import it into the new project and be ready to go. Now if the CAN driver instead starts whining about some missing "relay module", then it was badly designed with tight coupling - it knows things about other modules that should be no business for a CAN driver, and consequently it also depends on other unrelated modules. That's a very bad state of affairs. The main problem is that tight coupling causes bugs to escalate through your whole program. Write a bug in the relay driver and suddenly the CAN driver stops working too.
  • Also consider using hardware abstraction layers (HAL). CAN is a perfect example of when this is useful. I have one HAL for CAN drivers (prefixed `CAN`) which I re-use across a whole lot of different microcontrollers. The HAL is the user interface but also dictates which functions each driver needs to implement. The user calls the HAL, ensures that the correct drivers are linked to the project, and then everything just works. You can then port the code to another MCU with a minimum of effort, assuming that the CAN driver for that system is already written and tested. When using HAL, the prefix belongs to the HAL and not to the underlying drivers, which probably have some more cryptic name taken from the specific CAN Controller (FlexCAN, bxCAN or whatever it might be called).
#2: Post edited by user avatar Lundin‭ · 2022-09-26T08:46:38Z (over 1 year ago)
  • For what it's worth, I have some 20 years of experience designing embedded C systems, with large and small code bases both. Generally speaking, style and design matters become increasingly important when your code base grows. Code re-use and portability between projects is of course always nice too.
  • **Camel vs snake style**
  • Check out this interesting [research paper](http://www.cs.kent.edu/~jmaletic/papers/ICPC2010-CamelCaseUnderScoreClouds.pdf) regarding "CamelCase" vs "snake_case", which was carried out with eye tracking. Unsurprisingly they found that people used at reading one style or the other had it easier to read their preferred style. But also that when such bias was removed, camel case proved harder to read.
  • I have used all manner of styles over the years. I used to prefer camel at a time when I was doing a lot of PC programming, because it's more common there. Whereas snake is more common in embedded systems (and also in the *nix world). Generally I would say that when it comes to pure C (not C++), snake case code bases are more common.
  • Nowadays I solely use snake case and would recommend that if you have the option. Partially because of the above study, partially because it is more common in the code bases and protocol stacks etc you are likely to encounter when writing embedded C.
  • As for starting with lower/upper case using either style, that's still quite subjective and it's hard to argue for/against one or the other.
  • The most important thing of all though, is that you have a coding standard and that everyone follows it. It might be wise to separate _coding style_ (identifiers, indention, brace placement) from _coding guidelines_ (use this feature, don't use that feature). For example MISRA C mostly only covers the latter.
  • ---
  • **Identifier naming**
  • First of all please note that the C standard reserves a whole lot of identifiers. I won't go into this in detail since it's a big topic, but at least stay clear of all identifiers staring with an underscore, since they may collide with compiler libs.
  • Regarding constants and/or pre-processor macros, there is a wide consensus to use ALL_CAPS style for those. That's so common that I'd say it is an industry de facto standard, both in the PC world and the embedded world.
  • Regarding types, there's one very old but perhaps not necessarily common convention that types should be written starting with an upper case letter. I prefer to declare types with `_t` in the end instead, which is fine for embedded but not when coding POSIX.
  • Regarding identifiers for variables/functions: assuming you went with snake case, these should be lower case most of the time. _However_, I have long experience from designing and managing large embedded C code bases and one thing that really helps making code manageable is to use _source module prefixes_.
  • That is, if you are writing a CAN driver, you have for example some `can.h` and `can.c`. You would then prefix all your functions with `CAN_` or `can_` and prefix all constants `CAN_`, documenting that these belong to the `can.h` driver. They need to _start_ the name with this, so you'd write `can_init` and _not_ `init_can`. It has to be a prefix so that the reader can quickly see which module a function belongs to.
  • In your code templates for headers, you could have something in the top like `Prefix: CAN`. For the coding standard I've developed at my current company, we use something like this on top of each header:
  • ```c
  • /*
  • <legal/copyright stuff here>
  • File can.h
  • Replaces old_can.h
  • Status Active
  • Conformance MISRA C:2012 // filled in after passing code review
  • Author John Doe
  • Created 2022-09-26
  • Prefix CAN
  • Description This is a HAL for CAN drivers-...
  • */
  • ```
  • Further down you'll have the documentation for each function together with the prototype format function declaration. In this case maybe something like `can_err_t can_init (void);`, assuming you have created a common result/error type (some enum) for all functions in the driver (another good idea).
  • ---
  • > I have propositions to start our names with a module trigram?
  • In general, for the love of obfuscation please never invent new TLA. Huh, what's a TLA? Yeah exactly that... _three letter abbreviations_. In your case `CAN` is a standardized and well-known one (Controller Area Network), so the reader is expected to understand what it means. That's fine, it's an established term. They do not however have a clue what `CDR` is supposed to mean... recordable compact disc? You should be using `CAN` in this case.
  • However, letters are cheap - they are in fact free. So not everything has to be an evil 3-letter abbreviation. Naming your relay driver with the prefix `relay_` rather than `rel_` is in fact far more readable, so go with that.
  • > actually, the majority of our codes don't really have modules, how to name a new function inside?
  • You should start using more disciple when designing then. Sure, there will be the application level top-tier and it may not need to have prefixes or be organized in modules. But everything else, particularly drivers, protocol handlers, specific algorithms - these should have their own module. This is correct design according to object orientation and other popular ways of designing programs. It reduces tight coupling (important!), it allows code re-usage and it reduces namespace collisions.
  • If I am to do a new project with CAN, I should just be able to grab your CAN driver, import it into the new project and be ready to go. Now if the CAN driver instead starts whining about some missing "relay module", then it was badly designed with tight coupling - it knows things about other modules that should be no business for a CAN driver, and consequently it also depends on other unrelated modules. That's a very bad state of affairs. The main problem is that tight coupling causes bugs to escalate through your whole program. Write a bug in the relay driver and suddenly the CAN driver stops working too.
  • Also consider using hardware abstraction layers (HAL). CAN is a perfect example of when this is useful. I have one HAL for CAN drivers (prefixed `CAN`) which I re-use across a whole lot of different microcontrollers. The HAL is the user interface but also dictates which functions each driver needs to implement. The user calls the HAL, ensures that the correct drivers are linked to the project, and then everything just works. You can then port the code to another MCU with a minimum of effort, assuming that the CAN driver for that system is already written and tested. When using HAL, the prefix belongs to the HAL and not to the underlying drivers, which probably have some more cryptic name taken from the specific CAN Controller (FlexCAN, bxCAN or whatever it might be called).
  • For what it's worth, I have some 20 years of experience designing embedded C systems, with large and small code bases both. Generally speaking, style and design matters become increasingly important when your code base grows. Code re-use and portability between projects is of course always nice too.
  • **Camel vs snake style**
  • Check out this interesting [research paper](http://www.cs.kent.edu/~jmaletic/papers/ICPC2010-CamelCaseUnderScoreClouds.pdf) regarding "CamelCase" vs "snake_case", which was carried out with eye tracking. Unsurprisingly they found that people used at reading one style or the other had it easier to read their preferred style. But also that when such bias was removed, camel case proved harder to read.
  • I have used all manner of styles over the years. I used to prefer camel at a time when I was doing a lot of PC programming, because it's more common there. Whereas snake is more common in embedded systems (and also in the *nix world). Generally I would say that when it comes to pure C (not C++), snake case code bases are more common.
  • Nowadays I solely use snake case and would recommend that if you have the option. Partially because of the above study, partially because it is more common in the code bases and protocol stacks etc you are likely to encounter when writing embedded C.
  • As for starting with lower/upper case using either style, that's still quite subjective and it's hard to argue for/against one or the other.
  • The most important thing of all though, is that you have a coding standard and that everyone follows it. It might be wise to separate _coding style_ (identifiers, indention, brace placement) from _coding guidelines_ (use this feature, don't use that feature). For example MISRA C mostly only covers the latter.
  • ---
  • **Identifier naming**
  • First of all please note that the C standard reserves a whole lot of identifiers. I won't go into this in detail since it's a big topic, but at least stay clear of all identifiers staring with an underscore, since they may collide with compiler libs.
  • Regarding constants and/or pre-processor macros, there is a wide consensus to use ALL_CAPS style for those. That's so common that I'd say it is an industry de facto standard, both in the PC world and the embedded world.
  • Regarding types, there's one very old but perhaps not necessarily common convention that types should be written starting with an upper case letter. I prefer to declare types with `_t` in the end instead, which is fine for embedded but not when coding POSIX.
  • Regarding identifiers for variables/functions: assuming you went with snake case, these should be lower case most of the time. _However_, I have long experience from designing and managing large embedded C code bases and one thing that really helps making code manageable is to use _source module prefixes_.
  • That is, if you are writing a CAN driver, you have for example some `can.h` and `can.c`. You would then prefix all your functions with `CAN_` or `can_` and prefix all constants `CAN_`, documenting that these belong to the `can.h` driver. They need to _start_ the name with this, so you'd write `can_init` and _not_ `init_can`. It has to be a prefix so that the reader can quickly see which module a function belongs to.
  • In your code templates for headers, you could have something in the top like `Prefix: CAN`. For the coding standard I've developed at my current company, we use something like this on top of each header:
  • ```c
  • /*
  • <legal/copyright stuff here>
  • File can.h
  • Replaces old_can.h
  • Status Active
  • Conformance MISRA C:2012 // filled in after passing code review
  • Author John Doe
  • Created 2022-09-26
  • Prefix CAN
  • Description This is a HAL for CAN drivers-...
  • */
  • ```
  • Further down you'll have the documentation for each function together with the prototype format function declaration. In this case maybe something like `can_err_t can_init (void);`, assuming you have created a common result/error type (some enum) for all functions in the driver (another good idea).
  • One thing I would recommend to avoid, is to mix in vague terms like "handler", "driver" etc in the identifier name. It's rather superfluous and it's very hard to read code that calls `can_handler(); //handles CAN`... this literally tells the reader nothing other than "do not worry your pretty head". Better names are specific: `can_read_rxfifo`, `can_send` or whatever the function is actually doing.
  • ---
  • > I have propositions to start our names with a module trigram?
  • In general, for the love of obfuscation please never invent new TLA. Huh, what's a TLA? Yeah exactly that... _three letter abbreviations_. In your case `CAN` is a standardized and well-known one (Controller Area Network), so the reader is expected to understand what it means. That's fine, it's an established term. They do not however have a clue what `CDR` is supposed to mean... recordable compact disc? You should be using `CAN` in this case.
  • However, letters are cheap - they are in fact free. So not everything has to be an evil 3-letter abbreviation. Naming your relay driver with the prefix `relay_` rather than `rel_` is in fact far more readable, so go with that.
  • > actually, the majority of our codes don't really have modules, how to name a new function inside?
  • You should start using more disciple when designing then. Sure, there will be the application level top-tier and it may not need to have prefixes or be organized in modules. But everything else, particularly drivers, protocol handlers, specific algorithms - these should have their own module. This is correct design according to object orientation and other popular ways of designing programs. It reduces tight coupling (important!), it allows code re-usage and it reduces namespace collisions.
  • If I am to do a new project with CAN, I should just be able to grab your CAN driver, import it into the new project and be ready to go. Now if the CAN driver instead starts whining about some missing "relay module", then it was badly designed with tight coupling - it knows things about other modules that should be no business for a CAN driver, and consequently it also depends on other unrelated modules. That's a very bad state of affairs. The main problem is that tight coupling causes bugs to escalate through your whole program. Write a bug in the relay driver and suddenly the CAN driver stops working too.
  • Also consider using hardware abstraction layers (HAL). CAN is a perfect example of when this is useful. I have one HAL for CAN drivers (prefixed `CAN`) which I re-use across a whole lot of different microcontrollers. The HAL is the user interface but also dictates which functions each driver needs to implement. The user calls the HAL, ensures that the correct drivers are linked to the project, and then everything just works. You can then port the code to another MCU with a minimum of effort, assuming that the CAN driver for that system is already written and tested. When using HAL, the prefix belongs to the HAL and not to the underlying drivers, which probably have some more cryptic name taken from the specific CAN Controller (FlexCAN, bxCAN or whatever it might be called).
#1: Initial revision by user avatar Lundin‭ · 2022-09-26T08:41:33Z (over 1 year ago)
For what it's worth, I have some 20 years of experience designing embedded C systems, with large and small code bases both. Generally speaking, style and design matters become increasingly important when your code base grows. Code re-use and portability between projects is of course always nice too.

**Camel vs snake style**

Check out this interesting [research paper](http://www.cs.kent.edu/~jmaletic/papers/ICPC2010-CamelCaseUnderScoreClouds.pdf) regarding "CamelCase" vs "snake_case", which was carried out with eye tracking. Unsurprisingly they found that people used at reading one style or the other had it easier to read their preferred style. But also that when such bias was removed, camel case proved harder to read.

I have used all manner of styles over the years. I used to prefer camel at a time when I was doing a lot of PC programming, because it's more common there. Whereas snake is more common in embedded systems (and also in the *nix world). Generally I would say that when it comes to pure C (not C++), snake case code bases are more common.

Nowadays I solely use snake case and would recommend that if you have the option. Partially because of the above study, partially because it is more common in the code bases and protocol stacks etc you are likely to encounter when writing embedded C.

As for starting with lower/upper case using either style, that's still quite subjective and it's hard to argue for/against one or the other. 

The most important thing of all though, is that you have a coding standard and that everyone follows it. It might be wise to separate _coding style_ (identifiers, indention, brace placement) from _coding guidelines_ (use this feature, don't use that feature). For example MISRA C mostly only covers the latter.

---

**Identifier naming**

First of all please note that the C standard reserves a whole lot of identifiers. I won't go into this in detail since it's a big topic, but at least stay clear of all identifiers staring with an underscore, since they may collide with compiler libs.

Regarding constants and/or pre-processor macros, there is a wide consensus to use ALL_CAPS style for those. That's so common that I'd say it is an industry de facto standard, both in the PC world and the embedded world.

Regarding types, there's one very old but perhaps not necessarily common convention that types should be written starting with an upper case letter. I prefer to declare types with `_t` in the end instead, which is fine for embedded but not when coding POSIX. 

Regarding identifiers for variables/functions: assuming you went with snake case, these should be lower case most of the time. _However_, I have long experience from designing and managing large embedded C code bases and one thing that really helps making code manageable is to use _source module prefixes_. 

That is, if you are writing a CAN driver, you have for example some `can.h` and `can.c`. You would then prefix all your functions with `CAN_` or `can_` and prefix all constants `CAN_`, documenting that these belong to the `can.h` driver. They need to _start_ the name with this, so you'd write `can_init` and _not_ `init_can`. It has to be a prefix so that the reader can quickly see which module a function belongs to.

In your code templates for headers, you could have something in the top like `Prefix: CAN`. For the coding standard I've developed at my current company, we use something like this on top of each header:

```c
/*
  <legal/copyright stuff here>

  File          can.h
  Replaces      old_can.h
  Status        Active
  Conformance   MISRA C:2012   // filled in after passing code review
  Author        John Doe
  Created       2022-09-26
  Prefix        CAN

  Description   This is a HAL for CAN drivers-...
*/
```

Further down you'll have the documentation for each function together with the prototype format function declaration. In this case maybe something like `can_err_t  can_init (void);`, assuming you have created a common result/error type (some enum) for all functions in the driver (another good idea).

---

> I have propositions to start our names with a module trigram?

In general, for the love of obfuscation please never invent new TLA. Huh, what's a TLA? Yeah exactly that... _three letter abbreviations_. In your case `CAN` is a standardized and well-known one (Controller Area Network), so the reader is expected to understand what it means. That's fine, it's an established term. They do not however have a clue what `CDR` is supposed to mean... recordable compact disc? You should be using `CAN` in this case.

However, letters are cheap - they are in fact free. So not everything has to be an evil 3-letter abbreviation. Naming your relay driver with the prefix `relay_` rather than `rel_` is in fact far more readable, so go with that.

> actually, the majority of our codes don't really have modules, how to name a new function inside?

You should start using more disciple when designing then. Sure, there will be the application level top-tier and it may not need to have prefixes or be organized in modules. But everything else, particularly drivers, protocol handlers, specific algorithms - these should have their own module. This is correct design according to object orientation and other popular ways of designing programs. It reduces tight coupling (important!), it allows code re-usage and it reduces namespace collisions.

If I am to do a new project with CAN, I should just be able to grab your CAN driver, import it into the new project and be ready to go. Now if the CAN driver instead starts whining about some missing "relay module", then it was badly designed with tight coupling - it knows things about other modules that should be no business for a CAN driver, and consequently it also depends on other unrelated modules. That's a very bad state of affairs. The main problem is that tight coupling causes bugs to escalate through your whole program. Write a bug in the relay driver and suddenly the CAN driver stops working too.

Also consider using hardware abstraction layers (HAL). CAN is a perfect example of when this is useful. I have one HAL for CAN drivers (prefixed `CAN`) which I re-use across a whole lot of different microcontrollers. The HAL is the user interface but also dictates which functions each driver needs to implement. The user calls the HAL, ensures that the correct drivers are linked to the project, and then everything just works. You can then port the code to another MCU with a minimum of effort, assuming that the CAN driver for that system is already written and tested. When using HAL, the prefix belongs to the HAL and not to the underlying drivers, which probably have some more cryptic name taken from the specific CAN Controller (FlexCAN, bxCAN or whatever it might be called).