Does a function have any storage class in C Language? - c

Does a function have any storage class in C Language?

The answer is no. According to http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf (draft of C99) and http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf (draft of C11):
6.2.4 Storage durations of objects
1 An object has a storage duration that determines its lifetime.
Functions aren't objects, so they have no storage.
6.2.2 Linkages of identifiers
3 If the declaration of a file scope identifier for an object or a function contains the storage-class specifier static, the identifier has internal linkage.
This says that static applied to a function affects its linkage (there is no storage it could apply to).

The C standard doesn't formally define the meaning of storage class.
It does define what a "storage-class specifier" is --- it is one of the keywords typedef, extern, static, _Thread_local, auto and register.
Functions can be declared with storage-class specifiers extern or static.
The standard does mention objects having "storage class" in several places, for example
If the array object has register storage class, the behavior is undefined
but it is never defined what a storage class of an object is. One could reasonably assume that this is the storage-class specifier keyword that appears in one of the declarations, but it remains unclear what happens if some declarations of the same object have a storage-class specifier and others don't. It is also never defined what is the storage class of an object that doesn't have any declaration with a storage-class specifier.
It seems that one should avoid talking about storage classes of objects or functions altogether, and instead use related notions of storage duration and linkage which are precisely defined by the standard. When necessary, use phrases like "storage-class specifier X appears in a declaration", but not "object/function has storage class X".

Related

Is a declaration of a variable inside a block also a definition?

The C11 standard specifies in section 6.7/5 which declarations are also definitions:
C11 6.7/5
A definition of an identifier is a declaration for that identifier
that:
— for an object, causes storage to be reserved for that object;
(...)
So is a declaration of a variable inside a block also a definition? For example:
void Bla(void) {
int a; // Is this declaration also a definition?
}
I have found the following two answers on stackoverflow, which state that declarations of variables inside blocks are also definitions:
https://stackoverflow.com/a/4769638
https://stackoverflow.com/a/45695028/9771101
However, the answer provided by "Michael Burr" refers to 6.2.2/2 "Linkages of identifiers" in order to explain that variable declarations in block scope are also definitions. For me, his reference does not answer my question. The answer in the second link does not provide any reference to the C standard. Is there any other paragraph in the C standard which can be used as a reference to confirm those answers?
Please provide a reference to the C standard.
Yes, a declaration of an "object" (the C standard avoids using the word "variable") at block scope is a definition, except when the declaration of that object uses the storage-class specifier extern, in which case it is not a definition.
Here is how to see that from the standard (all references are to N1570, which is the closest approximation to the official text of C2011 that is publicly available at no charge):
first, 6.2.2p6 says
the following identifiers have no linkage: ... a block scope identifier for an object declared without the storage-class specifier extern.
second, 6.7p5 says
A definition of an identifier is a declaration for that identifier that:
* for an object, causes storage to be reserved for that object;
and finally, 6.2.4 which you will need to read in its entirety, but the most important bits are in paragraph 5 and 6:
An object whose identifier is declared with no linkage and without the storage-class specifier static has automatic storage duration ... its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way.
So, if you declare an object at block scope without extern, it has no linkage. An object with no linkage has automatic storage duration, unless it was declared with static, in which case it has static storage duration instead, see the parts of 6.2.4 I didn't quote. An object with automatic storage duration has storage reserved for it upon entry to the block it was declared within, and an object with static storage duration has storage reserved for it at program start (again, see the parts of 6.2.4 I didn't quote). Therefore, any declaration of an object that gives it no linkage is a definition.
(A declaration of an object at block scope with extern gives it external linkage and is not a definition. If you don't see why that is after reading through all of the sections I quoted and also 6.9, please ask a new question specifically about that.)
Section 6.2.2p6 of the C standard states:
In the set of translation units and libraries that
constitutes an entire program, each declaration of a particular
identifier with external linkage denotes the same object or
function. Within one translation unit, each declaration of an
identifier with internal linkage denotes the same object or
function. Each declaration of an identifier with no linkage
denotes a unique entity.
The part that's missing is section 6.2.2p6:
The following identifiers have no linkage: an identifier declared to
be anything other than an object or a function; an identifier
declared to be a function parameter; a block scope identifier
for an object declared without the storage-class specifier extern.
A variable declared inside of a block that does not have a storage class specifier (i.e. static or extern) has no linkage, and each declaration of a variable with no linkage is a unique object. Because the declaration is unique, it also qualifies as a definition.
See also section 6.7p7:
If an identifier for an object is declared with no linkage,
the type for the object shall be complete by the end of its
declarator, or by the end of its init-declarator if it has
an initializer; in the case of function parameters (including in
prototypes), it is the adjusted type (see 6.7.6.3) that is required to
be complete.

What is the formal way to determine the linkage of a `_Thread_local` identifier?

This is a 'language-lawyer' type question about a corner case in the C11 Standard.
The rules that determine the linkage of an identifier in a C program are spelled out in
clause 6.2.2 of the C11 Standard. In particular, 6.2.2(5) states that (emphasis mine):
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.
In the case of a declaration such as _Thread_local int a; in a file scope, 6.2.2(5) above does not apply,
since _Thread_local is a storage specifier. None of the other provisions of 6.2.2 apply, either
(no static so (3) does not apply, not in block scope, is an object and not a parameter, so (6) is not applicable, etc.). So what
should the linkage of a be according to the Standard? Am I missing some other rules that determine the linkage in this case?
I understand that the intention is to make it have external linkage (which is how gcc treats this case) but how
does this follow from the Standard itself?
Note that is is perfectly ok to have a declaration like
static _Thread_local int a; extern _Thread_local int a; in which case 6.2.2 rules apply just fine making a have internal linkage (that extern notwithstanding).
Finally, the semantics of _Thread_local are not relevant here.
As I read it, per C11 6.2.4p4, at file scope _Thread_local applies to the thread of main(), effectively moving them as static or extern references in the { } block of main(), rather than auto, and left implementation-defined how thread functions other than main() have access to them. I agree it appears to be a defect that it does not mention that the defining declaration of any object that is _Thread_local should be required to have static or extern as additional qualifier, not just 'may appear' as a referencing declaration, in 6.7.1p2.

Is it guaranteed that global variables are always initialized to 0 with c99?

From 6.7.8.10 in the C99 standard:
If an object that has automatic storage duration is not initialized explicitly, its value is
indeterminate. If an object that has static storage duration is not initialized explicitly,
then:
— if it has pointer type, it is initialized to a null pointer;
— if it has arithmetic type, it is initialized to (positive or unsigned) zero;
— if it is an aggregate, every member is initialized (recursively) according to these rules;
— if it is a union, the first named member is initialized (recursively) according to these
rules.
Is a global variable of any type (array, structure, bitfield) always defined as a static storage?
Is it guaranteed that global variables are always initialized to 0 with c99?
Yes and no
static void *g_v_ptr; // initialized to a null pointer
C99 details a value, but not its representation. "it has pointer type, it is initialized to a null pointer" implies that the pointer has value of a null pointer. This may or may not be NULL. This may or may not be 0. A compiler may have many bit patterns that correspond to a null pointer. In any case, the g_v_ptr == NULL is true as well as g_v_ptr == 0, but the pointer may have a different bit representation than 0. Certainly a pattern of all zero bits is usually easy to implement and certainly the most likely implementation. Yet the spec is just squishy enough to allow for some non-zero bit pattern to be used.
A similar case can be made for floating point numbers.
In any case (IAC), the initialized value will equate to 0.
According to the C Standard (5.1.2 Execution environments)
1 Tw o execution environments are defined: freestanding and hosted. In
both cases, program startup occurs when a designated C function is
called by the execution environment. All objects with static storage
duration shall be initialized (set to their initial values) before
program startup. The manner and timing of such initialization are
otherwise unspecified. Program termination returns control to the
execution environment.
and (6.2.4 Storage durations of objects)
3 An object whose identifier is declared without the storage-class
specifier _Thread_local, and either with external or internal linkage
or with the storage-class specifier static, has static storage
duration. Its lifetime is the entire execution of the program and its
stored value is initialized only once, prior to program startup.
Yes. It's guaranteed (at least since C89). "Global variables" (either with internal or external linkage) have static storage duration. Any object with static storage is guaranteed to be zero initialized according to C99, 6.7.8 Initialization.
C99 draft, 6.2.4 Storage durations of objects:
3 An object whose identifier is declared with external or internal
linkage, or with the storage-class specifier static has static storage
duration. Its lifetime is the entire execution of the program and its
stored value is initialized only once, prior to program startup.
6.2.2 Linkages of identifiers describes the linkage of identifiers, particularly in relation to "global" variables:
3 If the declaration of a file scope identifier for an object or a function contains the storage- class specifier static, the identifier has internal linkage.22)
4 For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible,23) 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. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.
Ignoring the case which could lead to undefined behaviour, all file scope identifiers with either internal or external linkage and they all have static storage duration.
Yes, as far as they are stored into bss section.
Your linker script define it and (mainly) default linker scripts do that.
While you can manually store data in different section manually, global scoped variable too.
BTW is the startup code that is responsible of zero the section. If you are working with non standard platforms or your startup code is made by you, you must ensure that.

why are we going for auto-type storage class? [duplicate]

This question already has answers here:
Where is the C auto keyword used?
(9 answers)
Closed 7 years ago.
In C, why we go for storage classes? I heard that auto type is the same as the local variable. in that case, why we go for auto type?is there any special by using auto type instead of local variables which is not mentioned as auto.
for example,
int a=10;
and
auto int a=10;
both are stored in stack segment and scope of these variables is within the function.so what is the difference between these two? why we go for auto-type?
First of all, auto (keyword) is not a type specifier, it's a storage class specifier. Quoting from the standard,
An object has a storage duration that determines its lifetime. There are four storage
durations: static, thread, automatic, and allocated.
To quote C11, chapter §6.2.4, Storage durations of objects
An object whose identifier is declared with no linkage and without the storage-class
specifier static has automatic storage duration,[..]
and, regarding the linkage, (emphasis mine)
The following identifiers have no linkage: an identifier declared to be anything other than
an object or a function; an identifier declared to be a function parameter; a block scope
identifier for an object declared without the storage-class specifier extern.
So, local variables, satisfying above conditions are by default, having automatic storage duration. You don't have to explicitly specify the auto keyword.
OTOH, type-specifiers determine the type (of data or variables). Going by the standard definition of type
The meaning of a value stored in an object or returned by a function is determined by the
type of the expression used to access it.

c - Declaring a variable with both register and static storage classes

(ANSI-C 89)
Hi, is it possible to declare a variable both static and register ? When ever I try to do this I just get as an error massage: multiple storage classes in declaration specifiers
This is the code:
#include <stdio.h>
void f1(static int i);
int main()
{
static register int i;
i = 5;
f1(i);
}
void f1(static int i)
{
static int y =6;
y+=1;
printf("\n Y=%d \n",y);
}
and th
Both register and static are storage class specifiers, and at most one storage class specifier can be specified.
From the C11 Standard ISO/IEC 9899:2011:
6.7.1 Storage-class specifiers
Syntax
storage-class-specifier:
typedef
extern
static
_Thread_local
auto
register
Constraints
At most, one storage-class specifier may be given in the declaration specifiers in a declaration, except that _Thread_local may appear with static or extern.120)
120)See ‘‘future language directions’’ (6.11.5).
Every object in C has a storage duration, which is precisely one of the following: automatic, static, allocated, and (as of C11) thread-local.
With the exception of allocated storage, the storage duration of an object is determined by the linkage of the declared name that refers to the object. (Objects with allocated storage do not have any names associated with them.) Linkage of an identifier is determined by the storage-class specifier that is present in the declaration. Since an object can only have one type of linkage and one storage duration, the C language only allows you to specify one storage-class specifier (with an exception in C11 for _Thread_local).
The linkages and resulting storage durations are as follows:
static: internal linkage, static storage duration
extern: external linkage, static storage duration
auto, register: no linkage, automatic storage duration. Only allowed at block scope.
none: At block scope same as auto, at file scope same as extern.
As you can see, almost any two storage-class specifiers result in different, incompatible semantics. Therefore, the language simply forbids using more than one storage-class specifier, since for most combinations there it would not be clear which behaviour was requested. It seems that auto and register are the only two specifiers that could conceivably be applied together. C11 actually adds the exception that _Thread_local may appear together with either extern or static, resulting in the linkage of the latter and thread-local storage duration.
Different storage durations and linkages may require different implementations. Since variables with no linkage need to be unique per scope, they would usually be placed on the function call stack (if they need to be stored). By contrast, a variable with static storage duration needs to persist for the duration of the entire program and thus cannot be placed on a call stack, but instead needs to go in some other part of memory that's available throughout.
You wouldn't be able to that, because static variables are stored in the .bss memory region, but register is stored in a high speed CPU register.
https://en.wikipedia.org/wiki/.bss

Resources