Why Does the "Static" Keyword Have So Many Meanings in C and C++

Why does the static keyword have so many meanings in C and C++?

Adding new keywords to a language breaks backwards compatibility. So static gets used where its use might possibly mean something ( int arr[static 50] vs int arr[auto 50] or int arr[extern 50] ) and cannot syntactically appear in that location based its use in previous versions.

Though in that case adding a not_less_than context sensitive keyword in that position would not break previous code, it would add another keyword (so simple text editors which are keyword aware but not syntax aware would not know whether or not it is a keyword), and break the 'keywords are not context sensitive' simplification made in C.

What does static mean in C?

  1. A static variable inside a function keeps its value between invocations.
  2. A static global variable or a function is "seen" only in the file it's declared in

(1) is the more foreign topic if you're a newbie, so here's an example:

#include <stdio.h>

void foo()
{
int a = 10;
static int sa = 10;

a += 5;
sa += 5;

printf("a = %d, sa = %d\n", a, sa);
}

int main()
{
int i;

for (i = 0; i < 10; ++i)
foo();
}

This prints:

a = 15, sa = 15
a = 15, sa = 20
a = 15, sa = 25
a = 15, sa = 30
a = 15, sa = 35
a = 15, sa = 40
a = 15, sa = 45
a = 15, sa = 50
a = 15, sa = 55
a = 15, sa = 60

This is useful for cases where a function needs to keep some state between invocations, and you don't want to use global variables. Beware, however, this feature should be used very sparingly - it makes your code not thread-safe and harder to understand.

(2) Is used widely as an "access control" feature. If you have a .c file implementing some functionality, it usually exposes only a few "public" functions to users. The rest of its functions should be made static, so that the user won't be able to access them. This is encapsulation, a good practice.

Quoting Wikipedia:

In the C programming language, static
is used with global variables and
functions to set their scope to the
containing file. In local variables,
static is used to store the variable
in the statically allocated memory
instead of the automatically allocated
memory. While the language does not
dictate the implementation of either
type of memory, statically allocated
memory is typically reserved in data
segment of the program at compile
time, while the automatically
allocated memory is normally
implemented as a transient call stack.

And to answer your second question, it's not like in C#.

In C++, however, static is also used to define class attributes (shared between all objects of the same class) and methods. In C there are no classes, so this feature is irrelevant.

what's the difference meaning of the keyword static between c and c++?

static is probably the most confusingly overloaded keyword in both C and C++. It means different things in different places.

  • Within functions, static is a storage class, denoting variables which exist for the lifetime of the programme. So saying

    void f() {
    static int i = 0;
    }

    says that the value of i will be preserved between calls to f(). Other storage classes are the default auto (but beware the change in meaning in C++11), extern, and register, plus thread_local in C11/C++11.

  • At file scope (or namespace scope in C++), static is a linkage specifier. Functions and variables marked static in this way have internal linkage, and so are local to the current translation unit. What this means is that a function like

     static int f() {
    return 3;
    }

    can only be referenced by other functions inside the same .c file. This usage of static was deprecated in C++03 in favour of unnamed namespaces. I read somewhere it was undeprecated again in C++11.

  • In C++, when applied to a member function or member variable of a class, it means that the function or variable does not need a class instance in order to be accessed. There is little different between "class static" member functions/variables and global functions/variable in terms of implementation, except that C++ class access specifiers apply to members.

  • One last one: in C99 (but not C++), static can be used within an array function parameter, like so:

    void f(int a[static 4]) {
    }

    this specifies that the parameter a must by an integer array of size at least 4.

I think that's all of them, but let me know in the comments if there are any I've forgotten!

The static keyword and its various uses in C++

Variables:

static variables exist for the "lifetime" of the translation unit that it's defined in, and:

  • If it's in a namespace scope (i.e. outside of functions and classes), then it can't be accessed from any other translation unit. This is known as "internal linkage" or "static storage duration". (Don't do this in headers except for constexpr. Anything else, and you end up with a separate variable in each translation unit, which is crazy confusing)
  • If it's a variable in a function, it can't be accessed from outside of the function, just like any other local variable. (this is the local they mentioned)
  • class members have no restricted scope due to static, but can be addressed from the class as well as an instance (like std::string::npos). [Note: you can declare static members in a class, but they should usually still be defined in a translation unit (cpp file), and as such, there's only one per class]

locations as code:

static std::string namespaceScope = "Hello";
void foo() {
static std::string functionScope= "World";
}
struct A {
static std::string classScope = "!";
};

Before any function in a translation unit is executed (possibly after main began execution), the variables with static storage duration (namespace scope) in that translation unit will be "constant initialized" (to constexpr where possible, or zero otherwise), and then non-locals are "dynamically initialized" properly in the order they are defined in the translation unit (for things like std::string="HI"; that aren't constexpr). Finally, function-local statics will be initialized the first time execution "reaches" the line where they are declared. All static variables all destroyed in the reverse order of initialization.

The easiest way to get all this right is to make all static variables that are not constexpr initialized into function static locals, which makes sure all of your statics/globals are initialized properly when you try to use them no matter what, thus preventing the static initialization order fiasco.

T& get_global() {
static T global = initial_value();
return global;
}

Be careful, because when the spec says namespace-scope variables have "static storage duration" by default, they mean the "lifetime of the translation unit" bit, but that does not mean it can't be accessed outside of the file.

Functions

Significantly more straightforward, static is often used as a class member function, and only very rarely used for a free-standing function.

A static member function differs from a regular member function in that it can be called without an instance of a class, and since it has no instance, it cannot access non-static members of the class. Static variables are useful when you want to have a function for a class that definitely absolutely does not refer to any instance members, or for managing static member variables.

struct A {
A() {++A_count;}
A(const A&) {++A_count;}
A(A&&) {++A_count;}
~A() {--A_count;}

static int get_count() {return A_count;}
private:
static int A_count;
}

int main() {
A var;

int c0 = var.get_count(); //some compilers give a warning, but it's ok.
int c1 = A::get_count(); //normal way
}

A static free-function means that the function will not be referred to by any other translation unit, and thus the linker can ignore it entirely. This has a small number of purposes:

  • Can be used in a cpp file to guarantee that the function is never used from any other file.
  • Can be put in a header and every file will have it's own copy of the function. Not useful, since inline does pretty much the same thing.
  • Speeds up link time by reducing work
  • Can put a function with the same name in each translation unit, and they can all do different things. For instance, you could put a static void log(const char*) {} in each cpp file, and they could each all log in a different way.

What is the exact reason for the keyword static working differently for variables and functions

In fact keyword static has the same meaning for functions and variables when it is used as the specifier of the linkage that is functions and variables in namespaces declared with keyword static have internal linkage.

From the C++ Standard (3.5 Program and linkage)

3 A name having namespace scope (3.3.6) has internal linkage if it is
the name of — a variable, function or function template that is
explicitly declared static

Static functions are stored the same way as other functions except that their names are not exported as external names.

This keyword is overloaded for variables. it also denotes static storage duration. It is what you are speaking about in your post.

From the C++ Standard (3.7.1 Static storage duration)

1 All variables which do not have dynamic storage duration, do not
have thread storage duration, and are not local have static storage
duration. The storage for these entities shall last for the duration
of the program (3.6.2, 3.6.3).

3 The keyword static can be used to declare a local variable with
static storage duration.

4 The keyword static applied to a class data member in a class
definition gives the data member static storage duration.

There is a third meaning of the keyword static in C++ relative to members of a class (in C there is no classes so this is not valid for C).

1 A data or function member of a class may be declared static in a
class definition, in which case it is a static member of the class.

Is static keyword necessary both in functions' prototype and definition in C?

has the foo only an internal linkage or such usage is incorrect?

6.2.2 Linkage of identifier states:

For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible,31) if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration.

When the foo definition says it has external linkage (functions have external linkage if none specified explicitly1) and at that point, there was a prior declaration of foo with internal linkage is visible. So foo has internal linkage.

1:

If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined exactly as if it were declared with the storage-class specifier extern. If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.

Why does static have different meanings depending on the context?

Your examples are all correct, however, they all share a common feature. The word static means that an enclosing instance is not necessary.

  • Only a static inner class can exist without an enclosing instance. For example, if you have a class Foo and a non-static inner class Bar then you cannot create an instance of Bar outside an instance of Foo.

  • A static method means you do not need an instance of the class to call the method. You can call String.format without an actual String instance for example.

  • A static field will exist even without an instance of the class. If your Foo class has a counter field that is static you can access it without ever instantiating an instance of the Foo class.

Consider, as a clarifying point, that an interface can have static classes, static fields, and static methods. However, it cannot have the non-static version of any of those things (ignoring default methods which are sort of ad-hoc'd into the concept). This is because you can never create an instance of an interface so there could never be an enclosing instance.

You can also declare inner interfaces, annotations, and enums to be static although the keyword in that case is entirely redundant (e.g. similar to declaring an interface method abstract). Interfaces, annotations, and enums have no relationship to an enclosing class to begin with so static can't really take that away.

One last byzantine point. If you do a static import (import static pack.age.Foo.*) you will be able to make unqualified references to any static items in a class (including interfaces, annotations, and enums regardless of whether or not they are redundantly marked static).

What does static variable in general mean for various programming language and circumstances?

Well, I think the keyword is appropriate. It means the variable you declare as static will remain stored at the same location throughout the whole execution of your program.

I thought static means doesn't change

This corresponds to the const keyword. Const implies it doesn't change, static implies it doesn't "move", as to it stays stored at the same location.

What does `static` mean in c#?

In short, static effectively means "associated with a type instead of any one instance of the type". So there's one set of static variables for a type (within an AppDomain) whether you have 0 instances or a million; you don't need an instance to access a static member, etc.

The exact point of initialization of static variables depends on whether there's also a static constructor or not, but very broadly speaking it's "once, usually before anything significant happens in the class". (See this blog post for a more detailed description.)

While readonly fields can be either static or instance (i.e. related to the type or related to an instance of the type), const values are always implicitly static (they're compile-time constants, so it wouldn't make sense to have one copy per instance).

You may sometimes see static being described as "shared between all instances of a type" - I personally dislike that description, as it suggests that there has to be at least one instance... whereas actually, you don't need any instances in order to use a static member. I prefer to think of them as entirely separate, rather than being "shared" between instances.



Related Topics



Leave a reply



Submit