Not Keil specific; one for the 'C' experts:
Why would one put 'static' variables definitions in a header?
eg, in a header file:
/* * TCO count to temperature conversion table. */ static erTcoTableStruct tcoTableOPUS1[] = { /*{TCO,Temp,} */ {1,-99}, {4,-45}, {5,-40}, {8,-35}, {11,-30}, {16,-25}, {22,-20}, {29,-15}, {37,-10}, {48,-5}, {61,0}, {78,5}, {99,10}, {124,15}, {153,20}, {188,25}, {227,30}, {270,35}, {315,40}, {365,45}, {420,50}, {481,55}, {549,60}, {625,65}, {710,70}, {805,75}, {910,80}, {1010,85}, {1060,88} };
AIUI, the whole point of so-called "header" files in 'C' is to share stuff between source files;
But the whole point of the 'static' keyword (at file scope) in 'C' is to make stuff private so that it is not visible to other modules - ie, not shared.
So I can't see why one would want to have 'static' definitions in a header?!
Yes, you are correct. There would be no extern static UART_Buffer[ MAX_SIZE ];
Even though I am unsure as to the invalidity of doing so, generally I wouldn't do it. My prior post (with he link to the picture) showed that I did make 'extern static' data references. I don't remember why I was doing so. But out of 700+ only eight were of that type in an unproven code-monkey fragment.
--Cpt. Vince Foster 2nd Cannon Place Fort Marcy Park, VA P.S. I've really got to move my house now... later for a while.
Here's what VC thinks of that:
error C2159: more than one storage class specified
Did you compile that code at all?
If I've managed to unpick your explanation of your header file usage you seem to define all file scope variables in a header file and all function scope variables in the function. That doesn't make a lot of sense - why hide file scope declarations in a separate file, particularly if they are not referenced outwith that file?
More than anything else, though, there's no point in ignoring convention unless you have a compelling reason to do so, and the reasons you have given so far are not compelling. They add up to little more than 'I do it my way because it's my way'.
I guess I forgot about that last question of three files. Each .C module should have an associated .H file. If another .C module needs access to the other .C file functions, or .H data-allocation references, then it would include the associated .H file.
/* ** ** UART_Protocol.C */ #include "UART_CONFIG.H" #include "UART.H" #include "UART_ISR.H"
But in MY case I would have it this way:
/* ****************************************** ** UART_Protocol.C */ #define UART_Protocol_Module #include "Includes.H" #undef UART_Protocol_Module // non-MISRA
/* ** Includes.H */ #ifdef UART_Protocol_Module #include "UART_CONFIG.H" #include "UART.H" #include "UART_ISR.H" #else // Anything or nothing you need contain if // UART_Protocol.C didn't call this module #endif /* ****************************************** ** SPI Module */ #ifdef SPI_Module #include "SPI_Config.H" #include "SPI.H" #else // whatever else you might want if SPI.C // didn't include the file #endif /*
--Cpt. Vince Foster 2nd Cannon Place Fort Marcy Park, VA
P.S. I hate moving.
Dear Jack Sprat,
I do it this way because I realized a long time ago that the process of inclusion is typically unstructured, and I wanted to bring a method of structure to the inclusion process.
As most people know, a module that includes "87C51.H" in one file, and another file includes "87C51FB.H in another will run into errors that can be hard to track down.
By having a single and well controlled "Includes.H" file, you can control exactly what all project modules include, and the order of which they get included.
Vince darling,
Indeed, the consequences of compiling the wrong code are well understood.
That doesn't require those include files to contain file scope variable definitions, or, for that matter anything with the storage class static. Removing those things from the header files takes away the need for all the #ifdef/#undef/#endif stuff. If you want to stick all your #include statements in one include file that's absolutely fine.
Another concern I have is related to "Includes.H" itself. I don't like "super header files" because they may incur the need to recompile possibly the entire project (which might have a long compile and link time...) in case of only a minor change to one of its subordinates. But this is just my opinion.
I've not found this to be a problem with embedded stuff these days. I used to enjoy having enough time for a cup of tea.
I agree.
"Removing those things from the header files takes away the need for all the #ifdef/#undef/#endif stuff."
But I don't think that bit's true - you'd still need the conditionals to determine whether something was being defined, or being declared as extern?
Back to my original question (again):
Perhaps the author had been exposed to something like that captain's "all data outside functions must be in headers" - but not quite understood it?
So the code in question could actually be some half-baked implementation of a semi-understood scheme.
Which brings us back to the earlier conclusion that the author(s) really didn't know what he/she/they were doing!
That's why I suggested not putting them in the header file!
If a variable is referenced only within one source file it's defining declaration should be placed in that source file, not in an include file, ideally with storage type static. If it is used elsewhere the defining declaration should be placed in the source file and an extern declaration placed in the associated include file, to be included in another referencing source file as required. If anyone finds it more appealing (and the idea does have merits from a labour saving point of view) all the include files can be included by another single include file.
source.c: int i; static int j;
source.h: extern int i;
In other words, just do it the way it's been done for years. 'C' has been around for a long time and was used, at least in the early days, mainly by programmers who knew a good thing when they saw it. The conventions that exist generally have a sound basis.
Either that or an implementation of a half baked scheme. As seen earlier in this thread there's a common misconception that include files have some special properties understood by 'the system'. It's understandable - the fact they usually have the extension .h rather than .c could easily give that impression.
Once you undestrand what a DID is, you'll want to easily identify the data-item-descriptions which identifies and describes the scope, range, bounds, etc of each data-store allocated. This DID is part of the Pre-Code-Monkey phase, so it is not surprising to see 'lesser' programmers Willie-Nillie creating data-stores on the fly and without the cross reference to the DID document.
NOTE: I shall be moving, and cannot respond for several days, so this should be my last post (Yes, I know some of you shall enjoy this), but I just needed to pack the Sardine 'can' a little tighter.
Once you undestrand what a DID is, you'll want to easily identify the data-item-descriptions which identifies and describes the scope, range, bounds, etc of each data-store allocated.
Gosh, it does all sound so very exciting when you talk like a '70s teletype.
This DID is part of the Pre-Code-Monkey phase, so it is not surprising to see 'lesser' programmers Willie-Nillie creating data-stores on the fly and without the cross reference to the DID document.
Oh Vince! I am not worthy to receive your wisdom.
I hope you're not away blowing things up again you naughty boy!
Original question for this thread: I think the developer was a fool who didn't understand the meaning of static.
If it had been some semi-clever way to create multiple identical initialized variables, then the source code should have contained very explicit comments about this very specific (ab)use to make other developers aware of the very important issue.
I do not like static variables in a header file. If I play with grep, I want to know the meaning when I get a hit on "static" and <my_variable_name>.
If I see "static int my_variable;" in a header file, then I will have to do a scan of a lot of source and header files to figure out where that variable (or in this case potentially multiple instances) may end up.
But I do like to use a global include file for the majority of all other includes and important declarations.
As mentioned earlier, it makes sure that header files are included in the direct order. An alternative would be to write header files like:
#if !defined(XXX_H) #define XXX_H #include <yyy.h> #include <zzz.h> ... typedef struct { ... }; #endif // XXX_H
And as also mentioned earlier, it makes sure that all parts of the code is configured to build for the same target platform - no mixup of include files for LPC17xx and LPC23xx or other instances where the header files may be so similar that code written for one processor may actually compile even with the wrong header file used.
If I have a project that does allocate variables in a header file, then I make sure that the module that gets the variables will also see the corresponding external declaration, to catch incompatibilities. If I do change the variable to 16-bit unsigned, I want the compiler to verify that the external declaration isn't still saying 8-bit signed or something other silly.
The compiler can catch quite a lot of common errors, if source code is written and updated according to some rules.