c - pointer as an initializer for an object with static duration - c

I. Background for the question.
As for 6.7.8., 4) of the Standard:
All the expressions in an initializer for an object that has static
storage duration shall be constant expressions or string literals.
As for 6.2.4. 3) of the Standard:
An object whose identifier is declared with external or
internal linkage, or with the storage-class specifier static
has static storage duration.
As for 6.6. 7) of the Standard:
More latitude is permitted for constant expressions in
initializers.
and 6.6. 9):
An address constant is a null pointer,a pointer to an lvalue designating
an object of static storage duration, or a pointer to a function
designator; ...
Finally, in 6.3.2.1. 1) we read:
An lvalue is an expression with an object type or an incomplete type
other than void;
II. Question.
I have the following declarations in object.h :
struct class_check_s {
char blank;
};
struct class_check_s class_check = { 0 };
struct class_check_s *passed = &class_check;
struct object_vt_s {
/* ... */
struct class_check_s *safecheck;
/* ... */
};
object.h is included into object.c , in which i have the following piece of code:
struct object_vt_s object_vt = {
/* ... */
.safecheck= passed,
/* ... */
};
gcc is yelling at .safecheck= passed part:
error: initializer element is not constant
clang is similar:
error: initializer element is not a compile-time constant
But i thought that my situation is falling under 6.6. 9). I guess not? I cannot find the answer why exactly though.
What i am doing is kinda a little oop module mostly for studying purposes. I am trying to achieve some sort of a dynamic type checking inside of objects' "methods".

What 6.6 9 means by “a pointer to an lvalue…” is a pointer-value for an lvalue, that is, the address of an lvalue. While your struct class_check_s *passed is called a “pointer,” it is more specifically an object whose value is a pointer. When you write .safecheck = passed, you are not giving the compiler the value it wants for the initializer; you are telling it to get the value from passed.
You could write .safecheck = &class_check. This initializes safecheck to the address of class_check, and the compiler is able to describe that address to the linker so that the program loader can correctly adjust its value when the program starts.
However, with .safecheck = passed, the compiler nominally has to read the value of passed from storage. In theory, a good compiler could look at the initialization of passed, see it is initialized to &class_check, and use that value for the initialization. The C standard does not formally prohibit this, but it does not require it, and it would be unusual. Additionally, note the semantics here are a bit wonky: passed is not declared const, so its value could change, so why should any particular value of it be used when .safecheck = passed is compiled? Sure, it is all “compile-time” stuff, but that is adding semantics to the C language that are not specified by the C standard. As far as the semantics of C goes, passed does not exist (no storage is reserved for it) until program execution starts.

Related

why am i getting warnings errors due to assignment of a variable's address to a pointer in the global scope?

this the snip of the warning i was getting when i tried to compile the program.I am just getting started with pointers and this following program is being flagged by compiler for some reason I am not able comprehend. the code is as follows:
#include <stdio.h>
int dec = 0;
int *d;
d = &dec;
int main() {
return 0;
}
there is no error when I am stuffing these declarations in to main's body. the version of gcc I am using is gcc version 12.2.0(downloaded using MSYS2) and code editor MS visual code.can anybody post an explanation for this?
as i have stated above i have randomly started typing a program to get familiar with pointers, i expected there to be no variation in the treatment of pointers regardless of where they are being declared and intialised.
You're attempting to perform an assignment outside of a function, which is not allowed. What you can do is initialize:
int *d = &dec;
You may use only declarations in file scopes.
In the provided program you are using an assignment statement
d = &dec;
in the file scope. So the compiler issues an error.
Instead you could write for example
#include <stdio.h>
int dec = 0;
int *d = &dec;
int main( void ) {
return 0;
}
As the variable dec has static storage duration then the expression &dec is an address constant and my be used as an initializer for the variable d that also has static storage duration.
From the C Standard (6.7.9 Initialization)
4 All the expressions in an initializer for an object that has static
or thread storage duration shall be constant expressions or string
literals.
and (6.6 Constant expressions)
7 More latitude is permitted for constant expressions in initializers.
Such a constant expression shall be, or evaluate to, one of the
following:
— an arithmetic constant expression,
— a null pointer constant,
— an address constant, or
— an address constant for a complete object type plus or minus an
integer constant expression.
and
9 An address constant is a null pointer, a pointer to an lvalue
designating an object of static storage duration, or a pointer to a
function designator; it shall be created explicitly using the unary
& operator or an integer constant cast to pointer type, or
implicitly by the use of an expression of array or function type. The
array-subscript [] and member-access . and -> operators, the address &
and indirection * unary operators, and pointer casts may be used in
the creation of an address constant, but the value of an object shall
not be accessed by use of these operators.

Why register array names can be assigned to pointer variables without compiler error?

I have a question about register keyword in C.
I found that register array name(e.g. array) can be assigned to pointer variable while &array[0] cannot be.
Can you explain why array name can be assigned to pointer? Or, if someone already explained it, please let me know links so that I can take a look to get the answer. Thank you.
Here is what I tried:
I read cppreference which explains register keyword and it says:
register arrays are not convertible to pointers.
Also, I read C89 draft which says:
The implementation may treat any register declaration simply as an auto declaration. However, whether or not addressable storage is actually used, the address of any part of an object declared with storage-class specifier register may not be computed, either explicitly (by use of the unary & operator as discussed in 3.3.3.2) or implicitly (by converting an array name to a pointer as discussed in 3.2.2.1). Thus the only operator that can be applied to an array declared with storage-class specifier register is sizeof.
This looks like I can't assign register array name to pointer to get its address.
Moreover, to find the answer, I searched here and found this question:
Address of register variable. There are good answers, however, still I couldn't find the answer what I wanted.
Here is the code which I tested. I compiled this code through Clang with flag -std=c89:
register int array[10];
int* p;
p = array; // Compiled without warning or error
p = &array[0]; // Compiled with error which I expected
I expected both p = array; and p = &array[0]; caused compiled error, but only p = &array[0]; made a compile error.
This is a bug in the Clang compiler.
GCC shows an error on both lines.
In discussing the automatic conversion of “array of type” to “pointer to type”, C 2018 6.3.2.1 says:
… If the array object has register storage class, the behavior is undefined.
Further, C 2018 footnote 124 says:
… the address of any part of an object declared with storage-class specifier register cannot be computed, either explicitly (by use of the unary & operator as discussed in 6.5.3.2) or implicitly (by converting an array name to a pointer as discussed in 6.3.2.1)…
Obviously, p = array; converts array to a pointer, as discussed in 6.3.2.1, but this footnote (which is non-normative but tells us the intent in this case quite explicitly) says the value for that pointer cannot be computed.
Since the behavior is not defined by the C standard, a C implementation could define it as an extension. However, the inconsistent behavior between array and &array[0] suggests this is not a deliberate extension by Clang but is a mistake.

static struct initialization in c99

I have encountered a strange behaviour when using compound literals for static struct initialization in GCC in c99/gnu99 modes.
Apparently this is fine:
struct Test
{
int a;
};
static struct Test tt = {1}; /* 1 */
However, this is not:
static struct Test tt = (struct Test) {1}; /* 2 */
This triggers following error:
initializer element is not constant
Also this does not help either:
static struct Test tt = (const struct Test) {1}; /* 3 */
I do understand that initializer value for a static struct should be a compile-time constant. But I do not understand why this simplest initializer expression is not considered constant anymore? Is this defined by the standard?
The reason I'm asking is that I have encountered some legacy code written in GCC in gnu90 mode, that used such compound literal construct for static struct initialization (2). Apparently this was a GNU extension at the time, which was later adopted by C99.
And now it results in that the code that successfully compiled with GNU90 cannot be compiled with neither C99, nor even GNU99.
Why would they do this to me?
This is/was a gcc bug (HT to cremno), the bug report says:
I believe we should just allow initializing objects with static
storage duration with compound literals even in gnu99/gnu11. [...]
(But warn with -pedantic.)
We can see from the gcc document on compound literals that initialization of objects with static storage duration should be supported as an extension:
As a GNU extension, GCC allows initialization of objects with static
storage duration by compound literals (which is not possible in ISO
C99, because the initializer is not a constant).
This is fixed in gcc 5.2. So, in gcc 5.2 you will only get this warning when using the -pedantic flag see it live, which does not complain without -pedantic.
Using -pedantic means that gcc should provide diagnostics as the standard requires:
to obtain all the diagnostics required by the standard, you should
also specify -pedantic (or -pedantic-errors if you want them to be
errors rather than warnings)
A compound literal is not a constant expression as covered by the C99 draft standard section 6.6 Constant expressions, we see from section 6.7.8 Initialization that:
All the expressions in an initializer for an object that has static storage duration shall be
constant expressions or string literals.
gcc is allowed to accept other forms of constant expressions as an extension, from section 6.6:
An implementation may accept other forms of constant expressions.
interesting to note that clang does not complain about this using -pedantic
C language relies on an exact definition of what is constant expression. Just because something looks "known at compile time" does not mean that it satisfies the formal definition of constant expression.
C language does not define the constant expressions of non-scalar types. It allows implementations to introduce their own kinds of constant expressions, but the one defined by the standard are restricted to scalar types only.
In other words, C language does not define the concept of constant expression for your type struct Test. Any value of struct Test is not a constant. Your compound literal (struct Test) {1} is not a constant (and is not a string literal) and, for this reason, it cannot be used as an initializer for objects with static storage duration. Adding a const qualifier to it will not change anything since in C const qualifier has no relation whatsoever to the concept of constant expression. It will never make any difference in such contexts.
Note that your first variant does not involve a compound literal at all. It uses a raw { ... } initializer syntax with constant expressions inside. This is explicitly allowed for objects with static storage duration.
So, in the most restrictive sense, the initialization with a compound literal is illegal, while the initialization with ordinary { ... } initializer is fine. Some compilers might accept compound literal initialization as an extension. (By extending the concept of constant expression or by taking some other extension path. Consult compiler documentation to figure out why it compiles.)
Interestingly, the clang does not complain with this code, even with -pedantic-errors flag.
This is most certainly about C11 §6.7.9/p4 Initialization (emphasis mine going forward)
All the expressions in an initializer for an object that has static or
thread storage duration shall be constant expressions or string
literals.
Another subclause to look into is §6.5.2.5/p5 Compound literals:
The value of the compound literal is that of an unnamed object
initialized by the initializer list. If the compound literal occurs
outside the body of a function, the object has static storage
duration; otherwise, it has automatic storage duration associated with
the enclosing block.
and (for completeness) §6.5.2.5/p4:
In either case, the result is an lvalue.
but this does not mean, that such unnamed object can be treated as constant expression. The §6.6 Constant expressions says inter alia:
2) A constant expression can be evaluated during translation rather
than runtime, and accordingly may be used in any place that a constant
may be.
3) Constant expressions shall not contain assignment, increment,
decrement, function-call, or comma operators, except when they are
contained within a subexpression that is not evaluated.
10) An implementation may accept other forms of constant expressions.
There is no explicit mention about compound literals though, thus I would interpret this, they are invalid as constant expressions in strictly conforming program (thus I'd say, that clang has a bug).
Section J.2 Undefined behavior (informative) also clarifies that:
A constant expression in an initializer is not, or does not evaluate
to, one of the following: an arithmetic constant expression, a null
pointer constant, an address constant, or an address constant for a
complete object type plus or minus an integer constant expression
(6.6).
Again, no mention about compound literals.
Neverthless, there is a light in the tunnel. Another way, that is fully sanitized is to convey such unnamed object as address constant. The standard states in §6.6/p9 that:
An address constant is a null pointer, a pointer to an lvalue
designating an object of static storage duration, or a pointer to a
function designator; it shall be created explicitly using the unary &
operator or an integer constant cast to pointer type, or implicitly by
the use of an expression of array or function type. The
array-subscript [] and member-access . and -> operators, the address &
and indirection * unary operators, and pointer casts may be used in
the creation of an address constant, but the value of an object shall
not be accessed by use of these operators.
hence you can safely initialize it with constant expression in this form, because such compound literal indeed designates an lvalue of object, that has static storage duration:
#include <stdio.h>
struct Test
{
int a;
};
static struct Test *tt = &((struct Test) {1}); /* 2 */
int main(void)
{
printf("%d\n", tt->a);
return 0;
}
As checked it compiles fine with -std=c99 -pedantic-errors flags on both gcc 5.2.0 and clang 3.6.
Note, that as opposite to C++, in C the const qualifier has no effect on constant expressions.
ISO C99 does support compound literals (according to this). However, currently only the GNU extension provides for initialization of objects with static storage duration by compound literals, but only for C90 and C++.
A compound literal looks like a cast containing an initializer. Its value is an object of the type specified in the cast, containing the elements specified in the initializer; it is an lvalue. As an extension, GCC supports compound literals in C90 mode and in C++, though the semantics are somewhat different in C++.
Usually, the specified type is a structure. Assume that struct foo and structure are declared as shown:
struct foo {int a; char b[2];} structure;
Here is an example of constructing a struct foo with a compound literal:
structure = ((struct foo) {x + y, 'a', 0});
This is equivalent to writing the following:
{
struct foo temp = {x + y, 'a', 0};
structure = temp;
}
GCC Extension:
As a GNU extension, GCC allows initialization of objects with static storage duration by compound literals ( which is not possible in ISO C99, because the initializer is not a constant ). It is handled as if the object is initialized only with the bracket enclosed list if the types of the compound literal and the object match. The initializer list of the compound literal must be constant. If the object being initialized has array type of unknown size, the size is determined by compound literal size.
static struct foo x = (struct foo) {1, 'a', 'b'};
static int y[] = (int []) {1, 2, 3};
static int z[] = (int [3]) {1};
Note:
The compiler tags on your post include only GCC; however, you make comparisons to C99, (and multiple GCC versions). It is important to note that GCC is quicker to add extended capabilities to its compilers than the larger C standard groups are. This has sometimes lead to buggy behavior and inconsistencies between versions. Also important to note, extensions to a well known and popular compiler, but that do not comply with an accepted C standard, lead to potentially non-portable code. It is always worth considering target customers when deciding to use an extension that has not yet been accepted by the larger C working groups/standards organizations. (See ISO (Wikipedia) and ANSI (Wikipedia).)
There are several examples where the smaller more nimble Open Source C working groups or committees have responded to user base expressed interest by adding extensions. For example, the switch case range extension.
Quoting the C11 standard, chapter §6.5.2.5, Compound literals, paragraph 3, (emphasis mine)
A postfix expression that consists of a parenthesized type name followed by a brace-enclosed list of initializers is a compound literal. It provides an unnamed object whose value is given by the initializer list.
So, a compound literal is tread as an unnamed object, which is not considered a compile time constant.
Just like you cannot use another variable to initialize a static variable, onward C99, you cannot use this compound literal either to initialize a static variable anymore.

Is it undefined in C11 to modify the result of a function call, or access it after the next sequence point?

At C99§6.5.2.2p5 there's this little gem, bolded by me for the purpose of emphasizing the question:
If the expression that denotes the called function has type pointer to function returning an object type, the function call expression has the same type as that object type, and has the value determined as specified in 6.8.6.4. Otherwise, the function call has type void. If an attempt is made to modify the result of a function call or to access it after the next sequence point, the behavior is undefined.
This allowed us to return structs, for example:
struct foo { int foo;
char bar[2]; };
struct foo get_foo() {
struct foo return_value = { .foo = 42,
.bar = "x" };
return return_value;
}
... and assign that return value somewhere else from within the caller, for example:
int main(void) {
struct foo bar = get_foo(); /* Well defined because the return value
* is copied -before- the sequence point
* that terminates its storage duration */
printf("%s\n", bar.bar);
printf("%d\n", get_foo().foo); /* Again, well defined because the access
* occurs before the next sequence point
* (the function call). */
}
... whilst rendering examples like the following invalid:
int main(void) {
printf("%s\n", get_foo().bar); /* UB because there's a sequence point
* between the evaluation of the sub-
* expression `get_foo().bar` and the
* entrace to the function `printf` */
get_foo().bar[0]++; /* UB because an attempt is made to modify the
* result of a function call */
}
--
C11§6.5.2.2p5, however, is essentially the same paragraph but without the bolded text.
If the expression that denotes the called function has type pointer to function returning an object type, the function call expression has the same type as that object type, and has the value determined as specified in 6.8.6.4. Otherwise, the function call has type void.
Are those examples above that are undefined behaviour in C99 still undefined in C11? If so, which paragraphs invalidate them? If not, I gather there must be some extension of the storage duration of automatic values/objects returned; which section of the standard specifies that extension of storage duration?
Are those examples above that are undefined behaviour in C99 still undefined in C11?
The examples posed above that are well defined are still well defined.
The temporary lifetime of the object in this one "ends when the evaluation of the containing full expression or declarator ends", so this previously undefined example is now well defined:
printf("%s\n", get_foo().bar);
This example is still undefined behaviour, because an attempt is made to modify an object that has temporary lifetime:
get_foo().bar[0]++;
If so, which paragraphs invalidate them? If not, I gather there must be some extension of the storage duration of automatic values/objects returned; which section of the standard specifies that extension of storage duration?
As pointed out by Jens Gustedt in a comment, C11§6.2.4p8 seems to convey a slightly different meaning to the sentence that C99§6.5.2.2p5 contains which C11§6.5.2.2p5 omitted:
A non-lvalue expression with structure or union type, where the structure or union contains a member with array type (including, recursively, members of all contained structures and unions) refers to an object with automatic storage duration and temporary lifetime.36) Its lifetime begins when the expression is evaluated and its initial value is the value of the expression. Its lifetime ends when the evaluation of the containing full expression or full declarator ends. Any attempt to modify an object with temporary lifetime results in undefined behavior.
36) The address of such an object is taken implicitly when an array member is accessed.
It seems that a little reorganisation was performed; the "storage duration extension" sentence in C99 was changed and moved from the "function call" section to the "storage duration" section, where it fits better.
The only question remaining is whether or not the result of a function call is considered an lvalue. For every operator that produces an lvalue, it seems as though it is explicitly mentioned that the operator produces an lvalue. For example, C11§6.5.3.2p6 states that the unary * operator produces an lvalue providing its operand points at an object.
The function call operator, however, says nothing about producing an lvalue, so we must assume that it doesn't produce an lvalue. If that's not good enough, then consider C11§6.5.2.3p3 and p7, which say:
A postfix expression followed by the . operator and an identifier designates a member of a structure or union object. The value is that of the named member,95) and is an lvalue if the first expression is an lvalue.
If f is a function returning a structure or union, and x is a member of that structure or union, f().x is a valid postfix expression but is not an lvalue.
We can also deduce from these two paragraphs that the result of a function is not an lvalue, thus meeting the criteria for C11§6.2.4p8 (quoted above).
Footnote 95 is interesting but tangential to the discussion on hand:
95) If the member used to read the contents of a union object is not the same as the member last used to
store a value in the object, the appropriate part of the object representation of the value is reinterpreted
as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type
punning’’). This might be a trap representation.

Which part of the C standard allows this code to compile?

I was bug-fixing some code and the compiler warned (legitimately) that the function dynscat() was not declared — someone else's idea of an acceptable coding standard — so I tracked down where the function is defined (easy enough) and which header declared it (none; Grrr!). But I was expecting to find the details of the structure definition were necessary for the extern declaration of qqparse_val:
extern struct t_dynstr qqparse_val;
extern void dynscat(struct t_dynstr *s, char *p);
extern void qqcat(char *s);
void qqcat(char *s)
{
dynscat(&qqparse_val, s);
if (*s == ',')
dynscat(&qqparse_val, "$");
}
The qqcat() function in the original code was static; the extern declaration quells the compiler warning for this snippet of the code. The dynscat() function declaration was missing altogether; again, adding it quells a warning.
With the code fragment shown, it's clear that only the address of the variable is used, so it makes sense at one level that it does not matter that the details of the structure are not known. Were the variable extern struct t_dynstr *p_parseval;, you'd not be seeing this question; that would be 100% expected. If the code needed to access the internals of the structure, then the structure definition would be needed. But I'd always expected that if you declared that the variable was a structure (rather than a pointer to the structure), the compiler would want to know the size of the structure — but apparently not.
I've tried provoking GCC into complaining, but it doesn't, even GCC 4.7.1:
gcc-4.7.1 -c -Wall -Wextra -std=c89 -pedantic surprise.c
The code has been compiling on AIX, HP-UX, Solaris, Linux for a decade, so it isn't GCC-specific that it is accepted.
Question
Is this allowed by the C standard (primarily C99 or C11, but C89 will do too)? Which section? Or have I just hit on an odd-ball case that works on all the machines it's ported to but isn't formally sanctioned by the standard?
What you have is an incomplete type (ISO/IEC 9899:1999 and 2011 — all these references are the same in both — §6.2.5 ¶22):
A structure or union type of unknown content (as described in §6.7.2.3) is an incomplete
type.
An incomplete type can still be an lvalue:
§6.3.2.1 ¶1 (Lvalues, arrays, and function designators)
An lvalue is an expression with an object type or an incomplete type other than void; ...
So as a result it's just like any other unary & with an lvalue.
Looks like a case of taking the address of an object with incomplete type.
Using pointers to incomplete types is totally sane and you do it each time you use a pointer-to-void (but nobody ever told you :-)
Another case is if you declare something like
extern char a[];
It is not surprising that you can assign to elements of a, right? Still, it is an incomplete type and compilers will tell you as soon as you make such an identifier the operand of a sizeof.
your line
extern struct t_dynstr qqparse_val;
Is an external declaration of an object, and not a definition. As an external object it "has linkage" namely external linkage.
The standard says:
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, ...
this implies that if it has linkage the type may be incomplete. So there is no problem in doing &qqparse_val afterwards. What you wouldn't be able to do would be sizeof(qqparse_val) since the object type is incomplete.
A declaration is necessary to "refer" to something.
A definition is necessary to "use" something.
A declaration may provide some limited definition as in "int a[];"
What stumps me is:
int f(struct _s {int a; int b;} *sp)
{
sp->a = 1;
}
gcc warn the 'struct _s' is declared inside parameter list. And states "its scope is ONLY this definition or declaration,...". However it does not give an error on "sp->a" which isn't in the parameter list. When writing a 'C' parser I had to decide where the definition scope ended.
Focusing on the first line:
extern struct t_dynstr qqparse_val;
It can be divided into the separate steps of creating the type and the variable, resulting in this equivalent pair of lines:
struct t_dynstr; /* declaration of an incomplete (opaque) struct type */
extern struct t_dynstr qqparse_val; /* declaration of an object of that type */
The second line looks just like the original, but now it's referring to the type that already exists because of the first line.
The first line works because that's just how opaque structs are done.
The second line works because you don't need a complete type to do an extern declaration.
The combination (second line works without the first line) works because combining a type declaration with a variable declaration works in general. All of these are using the same principle:
struct { int x,y; } loc; /* define a nameless type and a variable of that type */
struct point { int x,y; } location; /* same but the type has a name */
union u { int i; float f; } u1, u2; /* one type named "union u", two variables */
It looks a little funny with the extern being followed immediately by a type declaration, like maybe you're trying to make the type itself "extern" which is nonsense. But that's not what it means. The extern applies to the qqparse_val in spite of their geographical separation.
Here's my thoughts relative to the standard (C11).
Section 6.5.3.2: Address and indirection operators
Constraints
Paragraph 1: The operand of the unary & operator shall be either a function designator, the result of a [] or unary * operator, or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier.
Paragraph 2: The operand of the unary * operator shall have pointer type.
Here, we don't specify any requirement on the object, other than that it is an object (and not a bitfield or register).
On the other hand, let's look at sizeof.
6.5.3.4 The sizeof and _Alignof operators
Constraints
Paragraph 1: The sizeof operator shall not be applied to an expression that has function type or an incomplete type, to the parenthesized name of such a type, or to an expression that designates a bit-field member. The _Alignof operator shall not be applied to a function type or an incomplete type.
Here, the standard explicitly requires the object to not be an incomplete type.
Therefore, I think this is a case of what is not explicitly denied is allowed.

Resources