[Icc-avr] Are 'local' vars in main automatuc or in bss?
Albert vanVeen
Albert.vanVeen at pertronic.co.nz
Sun Oct 28 14:02:11 PST 2007
You're quite right, this discussion is becoming a bit "complicated"
(although very interesting).
I have to say: hmm, yes, well....
Ton is mostly right in his theoretical arguments, and structural
programming used to be a sort of hobby of mine, but you've got to be a
bit practical sometimes, especially in an embedded environment, so Dave
is right to in many ways. For instance, if "extern int foo(void);" tells
you it's not defined in this module, whereas just "int foo(void" would
be defined somewhere within this module, than that's useful.
And although capitalising certain items might add some information (like
distinguishing macro or function), words in capitals distract and
certainly do not enhance readability, but this comes into areas of
personal (dis)likes and habits, and as Dave said: when used in another
module, who cares if something is a constant or a variable, generally
speaking.
The mentioning of C's shortcomings, which we've all long known, brings
back the question: why were Pascal-like languages abandoned some 10-15
years ago? I programmed in Pascal/Modula for ages until compilers became
near impossible to find, and I had to 'learn' C. I still get compiler
complains sometimes that "begin" is not defined.
But coming back to practice: I like to follow Tom's rules where
possible, but in the reality of complex control systems, reality forces
some diversions. This brings me to a real question for Tom:
"As a general rule in programming, variables should only ever be
written to from one place in code, unless you have good reason and take
special care."
I do not understand this statement at all. That is why global variables
are needed and exist: to be able to manipulate them as necessary,
otherwise you use aprameters. In anyone module of my 15-module test
systems I have to be able to set certain values & results as things
progress, quite apart from some initialisation in main.
Please clarify the theory behind this statement for me; I'm not aware of
reading this before.
Albert.
-----Original Message-----
From: icc-avr-bounces at imagecraft.com
[mailto:icc-avr-bounces at imagecraft.com] On Behalf Of David Brown
Sent: Monday, October 29, 2007 09:53 AM
To: Discussion list for ICCAVR and ICCtiny Users. You do NOT need
tosubscribe to icc-announce if you are a member of this.
Subject: Re: [Icc-avr] Are 'local' vars in main automatuc or in bss?
Jaspers, Ton wrote:
>> -----Original Message-----
>> From: David Brown
>>
>> Jaspers, Ton wrote:
>>>
>>>
>>>> -----Original Message-----
>>>> From: David Brown
>>>>
>>>> Hi Ton,
>>>>
>>>> Although it's not actually necessary, I always use "extern"
>>>> for function declarations in headers, for consistency with
>>>> declarations for variables
>>>> - I don't know if there is any difference between the two.
>>> Since 'extern' is a C-language keyword it is unknown what
>> may happen.
>>> Some compilers may just ignore it while others may complain
>> about it.
>>> For portability I would be very carefull with external on a
>> function
>>> prototype.
>>>
>> The brief checks I've now made suggest that there is no difference -
>> a function declaration without a body (and no "static") is a
>> declaration with external linkage, just as if it had "extern"
>> explicitly. It is certainly the case that using "extern" with
>> function declarations is always legal in all C compilers - there is
>> no portability question to consider. Thus I (and others on webpages
>> thrown up by a quick google) recommend always using "extern" with
>> functions declarations in header files for consistency.
>
> They are not declarations, they are function prototypes.
>
I believe you are wrong here. I don't know I'll be able to do a good
job of explaining this, but it's probably well beyond the interest of
most iccavr list readers, and more suitable for the comp.lang.c group.
A prototype is a function declaration that gives the type information
for the function. Non-prototype declarations were used in early K&R C
code, but have been deprecated at least since C89 and cause warnings or
errors in many compilers:
// Non-prototype declarations:
foo();
extern foo();
// Prototype declarations:
int foo(int x);
extern int foo(int x);
A "declaration" is a statement that tells the compiler about a name -
you cannot have a "prototype" that is not a declaration. The term
"prototype" is often used to refer to a function declaration that is not
a definition (i.e., "int foo(int x);" without a function body) - but
strictly speaking, a function definition is also a declaration and a
prototype (unless you allow out-of-date K&R style functions).
>
>>> Any prototype in the header is by defenition public IMHO. Most
>>> compilers will issue a warning if the function is declared static.
>>>
>> Any prototype declaration in a header *should* be a public one,
>
> Never declare a function in a header!
>
You *must* declare functions (and variables) before using them - if you
want to use a function from another module, it must be declared before
use. All prototype statements are declarations.
If you mean that you should never declare a function without giving its
prototype information (i.e., the bare "foo();" example above), then I
agree completely.
The use of "extern" before a function declaration is optional (look at
the rules of when a declaration has external or internal linkage), but I
recommend it for consistency and explicitly saying what you mean.
>
>> otherwise it does not belong in the header. But that's a programmer
>> convention - the compiler cannot enforce it in any way.
>>
>> If you have a declaration of a function prototype (with or without
>> "extern", but with no "static") in a header, and later have the
>> function defined as "static", then you will get an error or a warning
>> about inconsistent linkage.
>
> That is what I said.
>
>
>>> I do very much agree with your remarks about "global". That is why
>>> tend to talk about the "scope" of a variable rather then use words
>>> as local and global. It is my experience thet those words are very
>>> confusing. The C++ naming convention is better "public" and
>> "private".
>>> But even in the C++ realm there is a constant discussion about the
>>> scope of a public or a private variable. At least it gives
>> some more
>>> options to qualify a variable together with the static keyword
>>> already known from C.
>>>
>> "Public" and "private" in C++ have nothing to do with linkage, and
>> are only indirectly related to scope.
>
> That is what I said.
>
>> Private and public members
>> of a class
>> have the same linkage and scope - it's just that the private members
>> are hidden by the compiler from direct access for functions other
>> than methods of the same class (or its friends).
>
> In other words, they have a different scope.....
>
No, they have the same scope - but different access.
An easy way to think about scoping and access rules is to compare it to
a file system. Scoping is like using directories - sub-directories
provide nested scope, and it's clear that a variable "x" in a
sub-directory is not related to "x" in a different directory. "public"
and "private" are like file attributes - a "private" variable is like a
file which has only read-write access to its owner, while a "public"
variable has read-write access for everyone.
>
>>> BTW You wrote:
>>>
>>> #define true 1
>>> #define false 0
>>>
>>> There have been countless debates about this and much bandwidth has
>>> been lost on boolean discussions. I tend to avoid booleans
>> all together
>>> in examples. In my code I usually stick to the original K&R
>> definition
>>> of zero and non-zero and avoid the whole boolean issue (who
>> cares?).
>> You are correct that there have been countless debates on booleans in
>> C, but there are very good reasons for using boolean types - you are
>> explicitly stating that you only expect a true or false value. And
>> there are very good reasons for fixing them as 1 and 0. Defining
>> "false" to be 0 is obvious, since that's standard C.
>> Defining "true" as
>> 1 is almost as obvious - it's the result of !0 and gives a consistent
>> single value for "true".
>
> No it is not.
> Most compulers make a -1 (all ones). Check it by printing out
"!FALSE".
>
*You* check it - !0 gives 1 on any compiler I have tried. It's also
important to note that the operators ==, !=, <=, <, >, and >= will
always return "1" for true on any compiler (as required by the
standards, IIRC).
Anyway, it doesn't really matter what value "true" has, as long as it is
not zero. It is only relevant if you to write code such as "bool b = (x
== y); if (b == true) ..." - and everyone agrees that's bad code.
>
>> In C99, the <stdbool.h> header explicitly defines "false" as 0 and
>> "true" as 1.
>
> Stdbool.h is exactly the file that is subject of all those debates.
> Many don't use it, and for good reasons. As there are equally good
> reasons to use it as well.
>
No, <stdbool.h> is a serious attempt to *end* these arguments. It is a
solution that a good boolean type for C that works in the same way as
the great majority of home-made boolean types, and in the same way as
"bool" in C++. There are always going to be some people who complain,
but they are a minority.
Have a look at http://c-faq.com/bool/index.html for some useful
information.
In fact, have a look at http://c-faq.com/decl/extern.html,
http://c-faq.com/decl/index.html and the rest of the FAQ - it makes a
lot of what I've been saying clear.
>
>>> - First of all it is impossble to define a true boolean
>> variable in C.
>> No - but it is impossible to get a C compiler to type-check a boolean
>> type (it will always be treated as a number - thus "bool b = 2;" is
>> legal C). In C++, where bool is a built-in type, you can get better
>> checking.
>
> Exactly!
>
>
>> You can also use:
>>
>> typedef enum { false, true } bool;
>
> Yuck!
> But I know there are those that use it as a substitute for a boolean.
> But don't fool yourself in to believing this IS a boolean.
>
> The nature of the beast is exactly the same as an error number
> enummeration. The fact that it has only two members does not make it
> a boolean. It is an enumaration and only that.
>
You can't have a true boolean in C, as there is no way to type-check the
boolean. But similarly, you can't have true enumerations (they are not
checked properly - C++ is slightly better). You can even argue that
since a true array has a size and range checking, there are no true
arrays in C, and since an integer type has a limited range which is not
enforced by the compiler, there are no true integer types in C. The
fact is, C is a pretty limited language - it is missing crucial features
and has a poor type system (C++ improves it a little). But you use the
features you've got, and it's easy to make a boolean type that works for
most practical purposes. Discarding "bool" (whether from <stdbool.h>,
or a home-made equivalent) because it is not a separate type is simply
throwing the baby out with the bathwater.
>> which may give your compiler (though not iccavr, AFAIK) a
>> better chance
>> at warning about errors. But the disadvantage of this on the AVR is
>> that a "bool" is then 2 bytes long.
>
> Agree, and there are numerous good reasons to use an enumeration and
it
> allows good error checking and there are a tousand other reasons why
> this
> is good practice but it is not a true boolean.
>
>
>>> - C defines everyting not zero to be true. So this would go
>> horribly
>>> wrong:
>>>
>>> USHORT var = 10
>>> if ( var == true ).... Alt: if (!var == false )
>>> AAAAAHHHRRRGGG....
>>>
>> It does not make logical sense to compare a numeric variable with a
>> boolean constant - your code is therefore incorrect (even though the
>> compiler accepts it).
>>
>> One of the main points of using an explicit boolean type is that it
>> makes logical sense to write:
>> bool b = true;
>> if (b) {...}
>>
>> Writing "if (b == true)" is not only risky (if you are not sure that
>> you've set b correctly), but it is logically redundant, and generates
>> less efficient code.
>
> If it were a boolean this should not be a problem, but it is no
boolean.
If it were a true boolean, it would just be redundant and wasteful,
whereas with C booleans, it is incorrect code.
> People that use it often falsly believe it to be a boolean but it is
> just
> an enumeration. There fore it would be better to use something like:
>
> typedef enum { OK, ERROR } return_t ;
>
It can make sense to use enumerations like this when it makes the code
clearer, but it does not allow the compiler to do any better checking,
and thus has no advantage over using a true/false boolean (except if it
makes the sense of the code clearer to the reader).
> Just to avoid false believes that it is a boolean.
>
Enumerations like this have no better type checking than C booleans.
With C++, you get a bit better type checking with enumerations - you
also get the same improvements with the built-in boolean type.
>
>> Since there is no type safety on booleans, it is important to be sure
>> that you use them correctly - you can convert any C value to
>> a boolean
>> by using !!.
>>
>>> - MISRA (and K&R back in the 70's) advise us to use uppercase for
>>> constants. Thus true and false should at least be:
>>>
>>> #define TRUE 1
>>> #define FALSE 0
>>>
>>> Or perhaps:
>>>
>>> #define FALSE 0
>>> #define TRUE (!FALSE)
>>>
>> Some of MISRA's conventions are stuck in the 70's, before computers
>> supported small letters.
>
> So far MISRA is the best (only) coding standard that seems to be
widely
> accepted in the industry. That in itself makes it a great standard.
>
That's true - but it doesn't make it perfect. While most rules in MISRA
make sense, there are lots of ugly rules that do not. For example,
MISRA says you should write "if (1 == x) ..." rather than "if (x == 1)",
so that the common typo of using "=" instead of "==" is caught by the
compiler. It is far better to write the readable and clear form "if (x
== 1)", and use a compiler (or linter) that will catch the typo.
>> I'm not keen on shouting unnecessarily, and
>
> Childish nonsense reasoning.
>
Code should be written clearly, and should be easy to read and
understand. All-caps words stand out unnecessarily, and distract from
that. Therefore they are bad coding style.
>
>> thus use small letters in macro names and constants. I'm
>> also keen on
>
> I rather see that a coleagues acros the globe, from any other company
> are not confused. It may be an old convention but most of us use it
with
>
> success. Anyting that makes the code more readable, maintainable and
> more accessible to a broad audience should be supported.
>
It is certainly important to keep a consistent style - if I'm working
with code written in a noticeably different style from the one I use,
I'll adapt. For example, there are many different styles for indenting
code - consistency within a piece of code is more important than the
particular style used. And if it is a requirement that code be written
to a particular style, then that's fair enough. But I am not going to
advocate using an old-fashioned, ugly (IMHO, of course), and
inconsistent convention just because lots of other people use it.
>
>> consistency of use - code that uses a #define'd constant or a macro
>> should not have to know whether it is using a preprocessor
>> symbol or a
>> standard function or constant (or variable) - using upper
>> case only for
>> macros is an arbitrary rule which breaks that consistency.
>
> No it is not, one can be consistend in using uppercase for macro's:
>
> #define maxplayer 10
> int maxplayers ;
>
> ..
> 10000 lines onward:
>
> maxplayer = 11 ; /* AIAIAIAIAI */
>
> Can't happen if MAXPLAYER was used instead.
The compiler will catch the typo, so there is no problem here (of
course, the real problem here - as you no doubt know - is using two
identifiers that are far too similar).
But suppose you've used "MAXPLAYER", and then decide later that this
should not be a fixed constant, but a variable "int maxplayer"? Do you
then change all 10,000 lines of code to convert all "MAXPLAYER"
references to "maxplayer" ? Or do you use some ugly hack like "#define
MAXPLAYER maxplayer" just to make your code work?
I cannot, in any way, see why one would prefer to write
if (playerNo < MAXPLAYER) ...
rather than
if (playerNo < maxPlayer) ...
just because maxPlayer/MAXPLAYER happens to be a compile-time constant.
I cannot see why anyone writing code that uses the value should want
to know if it is a macro or a variable, and I cannot see why they should
*have* to know. Similarly, I cannot see why the user of a function-like
macro should have to know that it is a macro, and not a normal function.
And what about static consts, which will often be optimised as though
they were #define constants, or inline functions which work partly like
macros, partly like standard functions?
It is certainly convenient that tool-vendors header files generally use
all-caps for their macros and constants, as it reduces the risk of
namespace collisions with the rest of the program, but I see only
disadvantages of using all-caps in the program code.
>
> Given, the compiler issues an error in this stupid example but that
> is not always the case. Just replace it with a slightly more complex
> macro that substitutes some pointer, not intended for this purpose.
> Macro's cannot be treated like ordinary functions or variables.
Knowing
> something is a macro can be very usefull.
>
>
>>> Other yucky things I have seen:
>>>
>>> typedef enum { FALSE, TRUE } bool_t ;
>>> typedef struct { unsigned bool:1 } bool_t ;
>>>
>> I haven't seen the struct version - it would be ugly to use, generate
>> inefficient code, and would not do what the programmer seems to think
>> (it will not make "bool_t" take just a single bit).
>>
>> There is nothing wrong with the enum version, except that enums are
>> sized as ints.
>>
>>> And even uglier things that I shall not repeat.
>>> (On this list it's like swearing in a church).
>>>
>>>
>>> And then:
>>>
>>> You did not add a warning next to the "ticker" variable.
>>> If any function, other then the ISR writes to it your in
>> deep trouble.
>>> In my code such critical variables are surrounded by
>> warning conmments
>>> and exclamation marks.
>>>
>> Whether such comments are necessary or not depends on how
>> obvious it is
>> - the "volatile" qualifier is a warning in itself, and may be
>> sufficient
>> in short code. It's also a good example of "static" - there
>> is no way
>> to access it from outside the module. Incidentally, it is just as
>> important to be careful about how the "ticker" variable is read as to
>> how it is written.
>>
>> As a general rule in programming, variables should only ever
>> be written
>> to from one place in code, unless you have good reason and
>> take special
>> care.
>>
>>> This is actually one of my tests. If a job applicant fails to spot
>>> such a critical variable, he gest a minus point.
>>>
>> If the applicant fails to associate "volatile" and
>> "critical", he should
>> definitely get some minus points. But I'd also give minus points to
>
> Volatile and critical are totally different things.
>
> A simple memory mapped peripheral (without interrupts) is still a
> volatile
> variable to the code, however it is not critical. Volatile only
> instructs
> the compiler to reload the variable on every use and not use a
temporary
> buffer (register) that may still have a copy. A critical variable may
be
> changed by an interrupt service while you write it, giving
unpredictable
> results. A critical variable needs some sort of semaphore mechanism,
> a volatile variable does not.
>
I see you are using "critical" here in a very specific sense, rather
than just to mean "important and to be treated with special care".
Given that, your argument makes more sense.
>
>> anyone who added a redundant comment like "!!! Warning !!! Be careful
>> when writing to this variable !!!" to a variable declared "volatile".
>
> Nobody gets minus points for adding comments over here. Unless it is
> utterly
> useless like:
>
> a = 10 ; /* a is assigned the value of 10 */
>
> Such comments often end up at our departments notice board (culprit
> unknown ;-).
> That usually teaches them.....
>
>
>> Such comments shows that the programmer does not understand
>> "volatile",
>
> <....>
>
> _______________________________________________
> Icc-avr mailing list
> Icc-avr at imagecraft.com
> http://dragonsgate.net/mailman/listinfo/icc-avr
_______________________________________________
Icc-avr mailing list
Icc-avr at imagecraft.com
http://dragonsgate.net/mailman/listinfo/icc-avr
Scanned by Bizo Email Filter
More information about the Icc-avr
mailing list