views:

293

answers:

9

Hi, I've read that static variables are used inside function when one doesn't want the variable value to change/initialize each time the function is called. But what about defining a variable static in the main program before "main" e.g.

#include <stdio.h>

static double m = 30000;

int main(void)
{
value = m * 2 + 3;
}

Here the variable m has a constant value that won't get modified later in the main program. In the same line of thought what difference does it make to have these instead of using the static definition:

const double m = 30000;

or

#define m 30000  //m or M  

and then making sure here to use double operations in the main code so as to convert m to the right data type.

Thanks a lot...

+3  A: 

static for an object declared outside a function merely makes the object local to the translation unit (i.e. it can't be accessed from other .c files). It doesn't make it constant. That it was const is for. They are orthogonal so you can have one or the other or both.

e.g.

static const double m = 5;

The #define declares a macro which (in this case) can be used as a constant value. There's no object, so const doesn't apply as there's not object to be changed. As a consequence, you also can't take the address of a macro.

Charles Bailey
Just to add a little: `const` and `static` aren't quite as orthogonal in C++ as they are in C. In C++, a `const` variable defined outside a function is also `static` by default.
Jerry Coffin
@Jerry: Sure, but this is a C question and a beginner question, so it's probably a detail that isn't worth complicating the answer with.
Charles Bailey
Is orthogonal the right word? Or did you mean mutual? as u said we can either one or the other or both.
yCalleecharan
@yCalleecharan: I meant orthogonal. Whether an object has internal or external linkage (i.e. what `static` does) is independent of whether it is `const`.
Charles Bailey
Thanks. When I thought of orthogonal, I thought of orthogonal vectors where 1 component has no effect on the other orthogonal component :).
yCalleecharan
+3  A: 

static means that the variable will have static storage duration, and local visibility. In this case, it's being used for the "local visibility" part of that -- i.e. it means that m is visible only within this translation unit (essentially this file after it's prepocessed).

Jerry Coffin
+1  A: 

In the toplevel scope static means that the variable (or function) cannot be accessed outside this source file - it won't be made available to the linker, and won't cause any name conflicts when linked in. It has no effect on whether a variable is constant or not - in fact, such variables are often specifically non-constant so that initialization can be cached.

The difference between using const and #define is that the former allows the compiler to type-check your usage of a constant.

rampion
+1  A: 

The main difference is that with #define you leave the type system. The preprocessor has no notion of type safety, scope etc. So e.g. if you later try to write a loop like

for (int m = 0; m < size; m++) { ... }

you are up to a nasty surprise...

Also if you use #defines, you will only see the value of 30000 when debugging your code, not the name m. Which does not seem to make a big difference in this case, but when using meaningful constant and variable names, it does indeed.

Péter Török
Thanks. It's interesting to know this debugging tip.
yCalleecharan
+2  A: 

... change/initialize each time the function is called

You use the words "change" and "initialize" as though they were the same, but they aren't

void f(void) {
  static int a = 0;
  a++; // changed!
  printf("%d\n", a);
}

int main(void) {
  f(); f();
}

/* 
  # 1
  # 2
*/

When at file-scope (outside functions) static does not mean "const" as in "static value", but it means that the identifier can only be referred to in that translation unit.

So your first m without const can still be changed. Only const guards against changes. But if you omit static then if you link in a library or another object file that has the same non-static identifier at file-scope you will get conflicts at link-time.

Johannes Schaub - litb
+1  A: 

#define is a preprocessor operation and will cause all occurrences of m to be replaced by 30000 before the compilation phase happens. The other two examples are bona fide variables. The static variable exists in the translation unit in which it is declared and can be modified. The const variable is read-only.

fbrereto
+3  A: 

When you write const double m=3000; you are telling the compiler to create a symbol m in the object file that can be accessed from other files. The compiler may inline the value of m in the file where it is defined, but the symbol still has to be allocated for the purposes of separate compilation.

When you write #define m 3000 you are just using a syntactic convenience for writing the same constant in several places in the source file.

Pascal Cuoq
+1  A: 

If the value of m has to stay the same forever, then of course you can either use

static const double m = 30000; 

or

#define m 30000

Just note that in C const objects have external linkage by default, so to get the equivalent const declaration you have to use static const, not just const.

Also note that in C language const objects are not constants, but rather "constant variables". If you need a true constant (i.e. an entity that forms constant expressions), you have to use either #define or enum constant.

The latter is normally an issue with integral constants only. In your case of a double the approach with [static] const might work best.

AndreyT
A: 
static double m = 30000; 

double foo(double x, double y) {
    return x/m + y;
}

This doesn't win you anything. A copy of m has to be made to do the computation. Also if you do:

double bar( double x, double y) {
     m += x + y;
     return  m;
}

Then all calls to bar will change m. Static variables outside of functions (or classes) are really global variables with file scope. Other files can't get at them by extern

Static variables inside a function are still like global variables, except that even other functions in the same file can't see them directly.

const double m = 30000;

This is better and in many cases best. If the compiler sees this global const and then sees a reference to m then it knows that rather than generate code to load the value from where ever it is (which likely requires loading a literal address into a register first) to a register or stack position to do computations it can just make a register be 30000 or sometimes generate an instruction with 30000 encoded right in there.

The down side to this is that the compiler has to assume that other souce files will want to read m and has to actually store a copy as a variable (but a constant variable) in the object file.

I'm not sure if it is standard but you can sometimes do extern const double m = 30000; and the compiler will use 30000 to optimize and assume that another file actually has a copy of m that will be stored in the executable. You can also do static const double m = 30000; and the compiler can assume that no one else will expect that a copy of m is stored in the object code generated from this source file.

Doing

#define m 30000

is more risky. You will not get a warning or error if previously there was another m declared as a variable, constant, or function. Also, for preprocessor macros like this it is easy to mess up. For example:

#define BASE_ADDRESS 48
#define MY_OFFSET  9
#define MY_ADDRESS  BASE_ADDRESS+MY_OFFSET
...
  return MY_ADDRESS*4;

Yes, this is a stupid example, but what this looks like after the preprocessor gets done with it is

...
  return 48+9*4;

Which is

 return 48+(9*4);

And that's not what you probably wanted.

Another place where macros are bad is when you have large constants, such as strings. Strings require that they be addressable by pointer and are more difficult to optimize away than integers and floating point literal or constant numbers. You could easily make a very large program if you had lots of stuff like:

#define JIM "Jim"
#define JOHN "John"

and then used JIM and JOHN all over your programs because the compiler might not be able to see that you really only needed the strings "Jom" and "John" once in the program.

That being said, it is not uncommon to see constants being declared like that, and often they are properly done that way by people who know what they are doing.

nategoose
Thanks for the long explanation. So if I have all codes in a single file, then static const double m = 30000 is the best answer I presume.
yCalleecharan
All compilers will recognize two string literals being identical and will store them only once.
Tomas