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?!
It is also potentially a waste of memory - every inclusion of the header file will instantiate a copy of the static variable in it.
I don't think that's just "potentially" - it's for certain!
Especially in cases like the example I showed - which is quite a large table!!
Unfortunately, this seems to be a 'loophole' within the standard ,as no real information is defined for header files. This should, at the very least, generate a warning/error message.
According to spec: "If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined."
(A translation unit being a source file and all headers referenced in it.)
Furthermore, the only requirement of the 'translation enviornment' (ie: compiler/linker) is:
"A conforming implementation shall produce at least one diagnostic message (identified in an mplementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined."
But since each source file is it's own 'translation unit' there are no requirements to flag this usage.
Moral: You can really do some damage without knowing it. I hope none of this code is used within heavy machinery.
I hope none of this code is used within heavy machinery.
Don't worry, the code is in the very capable hands of the good old caption. Oh, by the way, he is the guy that protects us from the ultimate bad guys - his stuff explodes. Heavy enough for you ? ;-)
As long as the vector is outgoing.
I don't think so.
"no real information is defined for header files."
Header files are just verbatim text inclusion, so the Compiler itself knows nothing about them. They are effectively irrelevant as far as the Compiler is concerned.
"If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined."
But that's not happening here - the header file is just creating identifiers with internal linkage. Nothing else.
But since each source file is it's own 'translation unit' there are no requirements to flag this usage. is in effect what you stated: "the header file is just creating identifiers with internal linkage"
And since the header files are "just verbatim text inclusion" if its syntatically correct, including using static keyword, can be used. The 'loophole' being just that, that there either should be some limitation or flagging of this type of use within a non-source or non .c file.
Just my opinion.
Not to prolong this thread too much longer, but another discussion not broached deals with 'how efficient' this usage is.
To that end I found an article that may be of interest...
www.eetimes.com/.../showArticle.jhtml
I know it is syntactically correct - that wasn't the question.
The questions was why anyone would want to do it?
So you can further argue your point of view??
I think this question has been answered. The developer explained the reasons for why it was used, which is more than you can usually expect from a code snippet.
It was also estabished that this is not the most efficent way to code. But, the developer seems to be in high regard within this community and I personally have no issue with the way he wants to code something. If it is a preference, and it does not violate the responsibilities entrusted to an engineer regarding safety and reliability then it is allowed.
Would I use this approach? I believe that question has also been answered.
There is no absolutely correct way to code to solve a problem. There are only more efficient and effective ways to do it. If the coding solution is accomplished within established guidelines and is well documented so be it. The fix would be easy enough: static --> const
Finally, if it is expected that someone else will post the why to this question, knowing full well the bias of this thread regarding why you should not use this approach, given a choice, do you really expect someone to do this? Only if they like to argue a point.
As far as I'm concerned, this was nothing more than an academic exersize.
Cheers.
Are you referring to Cpt Vince?
He was not the developer of the code that I cited in my original post!
I think you've got sidetracked onto a discussion of the way he manages his header files. That wasn't my original question!
My question was, what could be the point in having static definitions in a header file (irrespective of how you manage your header files); in other words, what could be the point in having multiple identically-named and identically-typed but distinct objects in the files of a project?
"As far as I'm concerned, this was nothing more than an academic exersize."
Well, I've got code like that, and I can't see any good reason for it - so I was wondering if anyone could suggest one.
Unfortunately, the discussion got sidetracked into different ways of managing headers - which wasn't the point.
I congratulate you for your persistence!
The only halfway sensible reason I can come up with (which I think someone else already suggested) is to allow the instance of the struct local to each source file to modify its local instance at runtime. I'm sure someone, somewhere will have managed to find a reason to do this.
Regarding some of the other stuff in this thread:
For the confused: From the compiler's perspective include files don't exist, so special handling is not an option.
For the deluded: The convention in 'C' programming is that header files do not include any code that allocates storage. Everyone goes through the "oh but I've got this great way of using header files that's much better/safer/controlled than the usual way" during their learning curve. Fortunately most of them eventually realise that the conventional approach is the best one.
When you join a company or a project you adopt the existing conventions, even though those almost certainly aren't the best. Why would you join a community of (presumably) hundreds of thousands of 'C' programmers than decide not to follow convention?
I look forward to the responses...
Thanks!
"The only halfway sensible reason I can come up with (which I think someone else already suggested) is to allow the instance of the struct local to each source file to modify its local instance at runtime."
Yes - Mike Kleshov suggested it.
Anyone (else) got any other ideas?
Far more likely than not because they have no idea what they're doing.
Just because there are people doing something doesn't mean that valid reasons exist for doing it.
Yes, that is very much the impression I get from the code in question!
:-(
"Just because there are people doing something doesn't mean that valid reasons exist for doing it."
Indeed! But I wanted a "second opinion" - in case there was a valid reason that I just hadn't thought of!
Static has three distinct uses in C:
Not really. It has two distinct uses: it changes linkage from external to internal, or duration from automatic to static.
(2) A variable declared static within a module, (but outside the body of a function) is accessible by all functions within that module. It is not accessible by functions within any other module. That is, it is a localized global.
(3) Functions declared static within a module may only be called by other functions within that module. That is, the scope of the function is localized to the module within which it is declared.
These two are the same thing, really. Distinguishing between functions and variables serves no purpose in this case. 'static' limits the visibility of external definitions to the containing translation unit, regardless if those definitions are of variables or functions.
Interestingly, the header mentioned in my original post does also contain static function declarations!
AFAIKS, this really makes no sense at all, since it forces every file which includes the header to provided a definition of the function - otherwise you get a "function declared static but not defined" warning!
Again, this suggests to me that the only reason for all this is, in fact, that the author(s) had no idea what he/she/they were doing!
See reference above:
* Incompetence * Sloth * A bad character * Job security * Arrogance
I did a search of my active projects for the word "static" and looked for 'extern' in front of it.
I found eight out of 712 'statics'. [oops] http://i.imgur.com/CVowH.jpg
A note here: TheBCS project isn't finished and is currently on the back-burner (still on the stove though), so I *might* have debugged those out.
--Cpt. Vince Foster 2nd Cannon Place Fort Marcy Park, VA
P.S. Happy Easter!! (The celebration of the resurrection of Jesus Christ)
this is actually a different question.
There are no externs in my question; just statics in a header file.
PS. Yes, Happry Easter!
"He is risen indeed!"
Andy,
With all due respect, and after much ado, I shall answer that question of "why put 'static' in a header file?"
Simple. ALL data-allocation on a module-wide basis should be declared/allocated within its associated header file. ALL external data-references should also be in it's [external] associated .C file's header.
ONLY routine/function specific data-store should be allocated within the actual .C file.
That's my philosophy, and I'm sticking to it.
A #define MAX_SIZE would also be in that header file, so your 'static UART_Buffer[ MAX_SIZE ]; is clearly identified within that .H file.
OK - if that is your philosophy, that's fair enough.
But, presumably, this requires a mechanism to ensure that "file-local" (ie, "internal linkage") variables are not repeated in other files?
Thanks for the 'fair enough' comment.
And yes, the "required" mechanism is my
#ifdef UART_Module // Data Allocation #else // Data reference #endif
construct.
(Not to mention my "uber" #include "Headers.H" file total control freak method of inclusion).
But that's where it gets a bit confusing!
The whole point of making something static is so that it can not be externally referenced!
So, in this case, would you have, say:
#ifdef UART_Module static char private_uart_char; #else // No reference for private_uart_char #endif
yes?
Perhaps you could clarify what you mean by "module" here?
Is it a single compilation unit, or the collection of files which, together, form a "module"?
eg, if your UART "driver" consists of, say, a uart_input.c, a uart_output.c and a uart_isr.c - do you consider that to be three "modules", or one?
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 /*
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.
View all questions in Keil forum