PDA

View Full Version : A couple of C style/semantics questions about variables




Sydde
May 10, 2011, 07:19 PM
These are pretty trivial things:

In Objective C, you might observe something in a .m file that looks like

#import ThisClass.h

static id theSingletonInstance = nil;

@implementation ThisClass
...

@end

Which puts a variable (theSingletonInstance) in a specific location where code will be able to find it. But this declaration is outside any { scope }, so it is obviously not automatic. If you omit "static", what changes? I ask because I was once working on a program that had variables declared in a .h file, without the static specification, and they were, well, static.


Secondly, I am curious how people feel about using arguments as locals. As far as I can tell, they live on the stack, just above the return vector (or sometimes in registers, as with PPC) and C subroutines, as I read once long ago, do not clean up the stack upon return, so the caller might leave the argument frame in place if the subroutine is being called repeatedly in a loop (compiler optimization, perhaps). But really, how dangerous is it to alter the local value of arguments, once you no longer need the originals? Is it considered bad practice?



jiminaus
May 10, 2011, 07:44 PM
These are pretty trivial things:

In Objective C, you might observe something in a .m file that looks like

#import ThisClass.h

static id theSingletonInstance = nil;

@implementation ThisClass
...

@end

Which puts a variable (theSingletonInstance) in a specific location where code will be able to find it. But this declaration is outside any { scope }, so it is obviously not automatic. If you omit "static", what changes? I ask because I was once working on a program that had variables declared in a .h file, without the static specification, and they were, well, static.


Static at this level means something different then static does within the {} of a function or method. At this level, static means the variable is only accessible/visible within the current compilation unit, the current .m file in this context; that is the symbol is not exported and make visible to the linker. Without the static, the variable symbol would be exported publicly in the .o file and could be referred to in other in other compilation units. The linker in this case would resolve the external symbol in the other .o files by joining them to this exported symbol.

Furthermore, if you had another singleton class in another .m file that followed this same pattern of having a theSingletonInstance global variable, you'd get a linker error if they weren't both static, because the symbol theSingletonInstance would be defined and exported twice in two different .o files.



Secondly, I am curious how people feel about using arguments as locals. As far as I can tell, they live on the stack, just above the return vector (or sometimes in registers, as with PPC) and C subroutines, as I read once long ago, do not clean up the stack upon return, so the caller might leave the argument frame in place if the subroutine is being called repeatedly in a loop (compiler optimization, perhaps). But really, how dangerous is it to alter the local value of arguments, once you no longer need the originals? Is it considered bad practice?

In the C calling convention, it is the callee's responsibility to clean up the static after a call. But assuming someone's not hacking in assembler and just leaving the compiler to generate this code, I wouldn't be concerned with it. [EDIT: Callee should be caller in the paragraph.]

There's no danger is changing the local value of argument in terms of the stack. The only "danger" is if one expected the value to be changed in the callee as well.

Style-wise is another purely subjective story. Personally I was heavily influence by function programming, so I avoid changing the values of variables. I would be more inclined to assign the new value to a new variable, and let the compiler optimise it away, if necessary.

Sydde
May 10, 2011, 10:22 PM
Static at this level means something different then static does within the {} of a function or method. At this level, static means the variable is only accessible/visible within the current compilation unit, the current .m file in this context; that is the symbol is not exported and make visible to the linker. Without the static, the variable symbol would be exported publicly in the .o file and could be referred to in other in other compilation units. The linker in this case would resolve the external symbol in the other .o files by joining them to this exported symbol.
That seems odd to me. I would have expected variables to require explicit inclusion in order to be reachable across files (e.g., in a .h file). This highlights one advantage of Objective-C, being able to create long-lived private variable context.
Furthermore, if you had another singleton class in another .m file that followed this same pattern of having a theSingletonInstance global variable, you'd get a linker error if they weren't both static, because the symbol theSingletonInstance would be defined and exported twice in two different .o files.
Well, OK, I just tried that (one static, one not), got no warning from the linker (building from XCode), and the variables were the same entity. I shall henceforth be very careful with statics. It seems much safer to keep variables within object contexts.
In the C calling convention, it is the callee's responsibility to clean up the static after a call.
Hmm, that is not what I remember reading in IM (volume three, I think). I was writing in ML for my own amusement, so I had to understand calling conventions like that. That, and/or some other text, told me that C and Pascal had opposite argument order (classic Mac OS used the Pascal convention) and that Pascal expected stack clean-up upon return while C did not. Perhaps I was misinformed or misunderstood.
Style-wise is another purely subjective story. Personally I was heavily influence by function programming, so I avoid changing the values of variables. I would be more inclined to assign the new value to a new variable, and let the compiler optimise it away, if necessary.
I am heavily influenced by laziness. It seems like it could make sense to provisionally alter the argument value (e.g., to modify a path) in the first part of a routine and let the second part handle what it gets in that argument. But again, as you say, it is a matter of style.

jiminaus
May 10, 2011, 11:39 PM
Hmm, that is not what I remember reading in IM (volume three, I think). I was writing in ML for my own amusement, so I had to understand calling conventions like that. That, and/or some other text, told me that C and Pascal had opposite argument order (classic Mac OS used the Pascal convention) and that Pascal expected stack clean-up upon return while C did not. Perhaps I was misinformed or misunderstood.


You right. Pascal and C are opposite. Sorry I wrote callee and when I meant caller. See http://en.wikipedia.org/wiki/X86_calling_conventions.

chown33
May 11, 2011, 01:00 AM
Well, OK, I just tried that (one static, one not), got no warning from the linker (building from XCode), and the variables were the same entity. I shall henceforth be very careful with statics. It seems much safer to keep variables within object contexts.

Any variables declared as static are invisible outside the declaring compilation unit. So the fact that one is static automatically means that the "one not" is the sole externally visible variable. Thuse there is no conflict and no warning.

There is no need to "be very careful with statics", as long as you use the 'static' keyword. That's the purpose of the keyword: to restrict the scope.

If you want to cause an error, you'll have to try it with at least two variables without a 'static' qualifier.

You may also have to provide an initializer for both variables. It is not uncommon for code like this:
foo.c:
int foo;

bar.c:
int foo = 1;

to be treated by the compiler and linker like this:
foo.c:
extern int foo;

bar.c:
int foo = 1;

In other words, there is a single int variable named foo, which is initialized to 1 in bar.c. As long as there isn't a conflicting type or initializer, the linker may successfully turn the multiple definitions into a single consistent global variable with a uniquely determined initializer.

In olden tymes, the linker was dumber, and would only complain about multiple attempts to initialize the variable. It was ignorant of type, so it was possible to have extern int foo in one file and extern float foo in another, with exciting debugging sessions as a result.

Sander
May 11, 2011, 03:55 AM
It is not uncommon...

In fact, the C99 standard specifies this (6.2.2, paragraph 5): "If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external."

The word "static" is a bit overloaded in C. Where it is used to restrict scope to the current translation unit, perhaps a better keyword would have been "local". And arguably, this should have been the default behavior, requiring explicit confirmation to make objects visible outside. Perhaps even for functions - we'd be half-way to an object oriented programming language then :)

Sydde
May 11, 2011, 10:52 AM
The word "static" is a bit overloaded in C. Where it is used to restrict scope to the current translation unit, perhaps a better keyword would have been "local". And arguably, this should have been the default behavior, requiring explicit confirmation to make objects visible outside. Perhaps even for functions - we'd be half-way to an object oriented programming language then :)
Well, why not simply "private"(default)/"public", that seems clear enough, no?