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
Regarding the part "when to use extern"/external linkage for objects (not functions), the general rule of thumb for all C programs embedded or otherwise is: never. Check out Why is global evil? Al...
#2: Post edited
- Regarding the part "when to use `extern`"/external linkage for objects (not functions), the general rule of thumb for all C programs embedded or otherwise is: ***never***. Check out [Why is global evil?](https://software.codidact.com/posts/291186)
- Also note that declaring variables at file scope without neither `extern` nor `static` in C makes them subject to a fuzzy rule called "tentative definitions" and there's a lot that can be said about that dubious feature, but it is better to simply ***never*** use tentative definitions either.
- Now of course, there exist nearly no programming rule you should follow as strictly as ***never***, even if this one comes close...
- ---
- For embedded systems there is one acceptable exception: specifically when you have a register map directly corresponding to memory-mapped register hardware and that register map may be used by any library in your project. Then it would be acceptable to provide all such registers as `extern` in a header, to be defined by a a corresponding .c file. That is, if you want to be able to view the registers in a common debugger as if they were any other variable.
- There are three different flavours of debuggers here:
- - Excellent MCU-aware debuggers for embedded systems that know about MCU-specific hardware peripherals without you providing any particular info.
- - So-so debuggers that will let you view hardware peripheral registers but only if given info about them in an ELF file. And for the registers to end up in the ELF file after linking, a C file needs to define them and the linker script needs to tell the linker "this memory area is hands-off for you".
- - Awful debuggers (Eclipse...) that simply don't have a clue about microcontrollers or about "scary memory thingies". They will let you view registers if provided in an ELF file too but don't treat them any different than any other RAM cell and what they do with the memory area despite the linker script is anyone's guess. They might go ahead and corrupt the register memory map in case of hardware peripherals that clear flags by reading them etc.
Depending on if you picked a good, so-so or awful tool chain, you may need to adapt the source code accordingly.- More info here: [How to access a hardware register from firmware?](https://electrical.codidact.com/posts/276290)
- ---
- Now in your specific case, `pin_t` is actually not a hardware peripheral register, but an abstraction layer on top of it, so it should _not_ be shared around through global spaghetti. Rather, it should be local and private to the file using it. In general: writing generic HAL layers on top of GPIO rarely ends up well and is not something I recommend - it is very easy to create needless bloat that way since GPIO at least historically was very simple and straight-forward. But this is a whole story of its own.
- Regarding the part "when to use `extern`"/external linkage for objects (not functions), the general rule of thumb for all C programs embedded or otherwise is: ***never***. Check out [Why is global evil?](https://software.codidact.com/posts/291186)
- Also note that declaring variables at file scope without neither `extern` nor `static` in C makes them subject to a fuzzy rule called "tentative definitions" and there's a lot that can be said about that dubious feature, but it is better to simply ***never*** use tentative definitions either.
- Now of course, there exist nearly no programming rule you should follow as strictly as ***never***, even if this one comes close...
- ---
- For embedded systems there is one acceptable exception: specifically when you have a register map directly corresponding to memory-mapped register hardware and that register map may be used by any library in your project. Then it would be acceptable to provide all such registers as `extern` in a header, to be defined by a a corresponding .c file. That is, if you want to be able to view the registers in a common debugger as if they were any other variable.
- There are three different flavours of debuggers here:
- - Excellent MCU-aware debuggers for embedded systems that know about MCU-specific hardware peripherals without you providing any particular info.
- - So-so debuggers that will let you view hardware peripheral registers but only if given info about them in an ELF file. And for the registers to end up in the ELF file after linking, a C file needs to define them and the linker script needs to tell the linker "this memory area is hands-off for you".
- - Awful debuggers (Eclipse...) that simply don't have a clue about microcontrollers or about "scary memory thingies". They will let you view registers if provided in an ELF file too but don't treat them any different than any other RAM cell and what they do with the memory area despite the linker script is anyone's guess. They might go ahead and corrupt the register memory map in case of hardware peripherals that clear flags by reading them etc.
- Depending on if you picked an excellent, so-so or awful tool chain, you may need to adapt the source code accordingly.
- More info here: [How to access a hardware register from firmware?](https://electrical.codidact.com/posts/276290)
- ---
- Now in your specific case, `pin_t` is actually not a hardware peripheral register, but an abstraction layer on top of it, so it should _not_ be shared around through global spaghetti. Rather, it should be local and private to the file using it. In general: writing generic HAL layers on top of GPIO rarely ends up well and is not something I recommend - it is very easy to create needless bloat that way since GPIO at least historically was very simple and straight-forward. But this is a whole story of its own.
#1: Initial revision
Regarding the part "when to use `extern`"/external linkage for objects (not functions), the general rule of thumb for all C programs embedded or otherwise is: ***never***. Check out [Why is global evil?](https://software.codidact.com/posts/291186) Also note that declaring variables at file scope without neither `extern` nor `static` in C makes them subject to a fuzzy rule called "tentative definitions" and there's a lot that can be said about that dubious feature, but it is better to simply ***never*** use tentative definitions either. Now of course, there exist nearly no programming rule you should follow as strictly as ***never***, even if this one comes close... --- For embedded systems there is one acceptable exception: specifically when you have a register map directly corresponding to memory-mapped register hardware and that register map may be used by any library in your project. Then it would be acceptable to provide all such registers as `extern` in a header, to be defined by a a corresponding .c file. That is, if you want to be able to view the registers in a common debugger as if they were any other variable. There are three different flavours of debuggers here: - Excellent MCU-aware debuggers for embedded systems that know about MCU-specific hardware peripherals without you providing any particular info. - So-so debuggers that will let you view hardware peripheral registers but only if given info about them in an ELF file. And for the registers to end up in the ELF file after linking, a C file needs to define them and the linker script needs to tell the linker "this memory area is hands-off for you". - Awful debuggers (Eclipse...) that simply don't have a clue about microcontrollers or about "scary memory thingies". They will let you view registers if provided in an ELF file too but don't treat them any different than any other RAM cell and what they do with the memory area despite the linker script is anyone's guess. They might go ahead and corrupt the register memory map in case of hardware peripherals that clear flags by reading them etc. Depending on if you picked a good, so-so or awful tool chain, you may need to adapt the source code accordingly. More info here: [How to access a hardware register from firmware?](https://electrical.codidact.com/posts/276290) --- Now in your specific case, `pin_t` is actually not a hardware peripheral register, but an abstraction layer on top of it, so it should _not_ be shared around through global spaghetti. Rather, it should be local and private to the file using it. In general: writing generic HAL layers on top of GPIO rarely ends up well and is not something I recommend - it is very easy to create needless bloat that way since GPIO at least historically was very simple and straight-forward. But this is a whole story of its own.
