Does C allows non-const expressions in array initializer list? - c

In the following code a array is initialized with s "seed" variable, which is clearly not constant expression (as it's evaluated "run-time"):
#include <stdio.h>
int main(void)
{
int s = 1, i;
int a[] = {s, s + 2, s + 4, s + 6, s + 8};
for (i = 0; i < (int) (sizeof a / sizeof a[0]); i++)
printf("%d ", a[i]); /* prints: 1 3 5 7 9 */
putchar('\n');
return 0;
}
It compiles in gcc -Wall -Wextra with no warnings. However adding -pedantic provokes:
check.c: In function ‘main’:
check.c:8: warning: initializer element is not computable at load time
check.c:8: warning: initializer element is not computable at load time
check.c:8: warning: initializer element is not computable at load time
check.c:8: warning: initializer element is not computable at load time
check.c:8: warning: initializer element is not computable at load time
Does C require constant expression for initializer elements ?

This is valid in c99 but not valid in c89 (emphasize mine):
(C89, 6.5.7) "All the expression in an initializer for an object that has static storage duration or in an initializer list for an object that has aggregate or union type shall be constant expressions"
but
(C99, 6.7.8p4) "All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals."
By default, gcc compiles with -std=gnu89 which is c89 + GNU extensions.

In addition to ouah's excellent answer I would add that C99 requires constant expression for designators within designated initializers (only in C99), e.g. following array initialization is invalid in C99:
int s = 1, i = 0;
int a[] = {[i] = s, [i+1] = s + 2, [i+2] = s + 4, s + 6, s + 8};
which might be rewritten as e.g.:
#define I 0
int s = 1, i;
int a[] = {[I] = s, [I+1] = s + 2, [I+2] = s + 4, s + 6, s + 8};

Related

C program will not compile: it shows "lvalue" error

#include <stdio.h>
int main()
{
int ary[2][3];
foo(ary);
}
void foo(int (*ary)[3])
{
int i = 10, j = 2, k;
ary[0] = &i;
ary[1] = &j;
for (k = 0;k < 2; k++)
printf("%d\n", *ary[k]);
}
I tried it with many different compilers but I do not understand why this will not compile.
You're assigning to an expression with an array type.
ary inside foo is a variable of type "pointer to array of three ints".
When you assign to it, you're trying to assign a variable of type "pointer to int" to a variable of type "array of three ints".
This is invalid because an array is not an lvalue (6.3.2.1p3):
Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
#include <stdio.h>
void foo(int (*ary)[3]);
int main()
{
int ary[2][3];
int (*x)[3] = &ary[0];
foo(&ary[0]);
}
void foo(int (*ary)[3])
{
int i = 10, j = 2, k;
*ary[0] = i;
*ary[1] = j;
for (k = 0;k < 2; k++)
printf("%d\n", *ary[k]);
}
In C language array, structure and union always pass by with reference. C language not strictly check reference type and also support implicit casting.
void foo(int (*ary)[3]) this is a syntax of passing a function to a function as reference (call back function). but you trying to assign a value to function which is implicitly cast by c does not matter you pass a array reference. that why its showing lvalue error.
LValue implies that if you assign some value using assignment operator (=) there left side must be a variable but in your case it's a callback reference.
Hope its help.

pointer to a array of initialized integers

I am trying to declare a pointer to a array of initialized ints at once(gcc 5.2.0, gnu99)
This is working
int a1[] = {1, 2, 3, 4, 5};
int (*a)[] = &a1;
I tried this and it isn't
int *why = (int p[2]) {1,2};
../src/gps/gps.c:399:18: error: expected ')' before 'p'
int *why = (int p[2]) {1,2};
^
int (*b)[5]= (int(*)[5])&({11,2,3,5,6});
../src/gps/gps.c:400:31: warning: left-hand operand of comma expression has no effect [-Wunused-value]
int (*b)[5]= (int(*)[5])&({11,2,3,5,6});
^
int (*cc)[] = &{1, 2, 3, 4, 5}
../src/gps/gps.c:402:17: error: expected expression before '{' token
int (*cc)[] = &{1, 2, 3, 4, 5}
^
What I miss here?
Here's the proper way to define these:
int *why = (int [2]) {1,2};
int (*a)[5]= &((int []){11,2,3,5,6});
When you create a compound literal, you prefix it with what looks like a typecast.
The first line didn't work because you attempted to put a variable name inside of the cast, and the second line didn't work because you didn't put the cast immediately before the part in curly braces.

semi-dynamic allocation code work in c++, but not in c, why?

below two codes works fine in c++ file, but compile error in c, why?
it seems to use const variable causing some problem in c,
i use dev c++ 5.11
19 3 C:\Users\tjc\Desktop\c練習\Untitled4.c [Error] variable-sized object may not be initialized
19 3 C:\Users\tjc\Desktop\c練習\Untitled4.c [Warning] excess elements in array initializer
19 3 C:\Users\tjc\Desktop\c練習\Untitled4.c [Warning] (near initialization for 'A')
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
int cmpW( const void* p1, const void*p2){
float *pf1 = (float*)p1;
float *pf2 = (float*)p2;
return pf1[0] - pf2[0];
}
int cmpH( const void* p1, const void*p2){
float *pf1 = (float*)p1;
float *pf2 = (float*)p2;
return pf2[1] - pf1[1];
}
int main(void)
{
const size_t n = 5;
float A[n][2] = {0}; //line 19
int i=0;
for(i=0; i<n; ++i){ // Data input.
printf("W H: ");
scanf("%f %f", &A[i][0], &A[i][1]);
}
qsort(A, n, sizeof(float) * 2, cmpW ); // By weight
for(i=0; i<n; ++i) // Data input.
printf("(%f, %f) ", A[i][0], A[i][1]);
printf("\n");
qsort(A, n, sizeof(float) * 2, cmpH ); // By height
for(i=0; i<n; ++i) // Data input.
printf("(%f, %f) ", A[i][0], A[i][1]);
printf("\n");
system("pause");
}
This is a difference in how C and C++ treat variables qualified as const. In C, a const variable is not considered to be a true constant, so the declaration float A[n][2] is considered a variable length array, even though n is declared as a const int.
From section 6.6 (Constant expressions) of the C standard:
8 An arithmetic constant expression shall have arithmetic type and shall only have operands that are integer constants,
floating constants, enumeration constants, character constants,
sizeof expressions whose results are integer constants, and
_Alignof expressions. Cast operators in an arithmetic constant expression shall only convert arithmetic types to arithmetic
types, except as part of an operand to a sizeof or
_Alignof operator.
Because A is considered a variable length array, it may not be initialized.
From section 6.7.9 (Initialization):
3 The type of the entity to be initialized shall be an array of unknown size or a complete object type that is not a
variable length array type.
I think, this is compiler spesific error, not const variable error. If you change the code as this, the same error still exists.
size_t n = 5;
float A[n][2] = {0};
or
int n = 5;
float A[n][2] = {0};
If you set g++.exe compiler for C from Tools->Compiler Options->Program in DevC++, the problem will solve. However, this is not safe. I want to explain the cause of the problem.

Is it the correct way to initialize array? [duplicate]

This question already has answers here:
Using non standard declaration of array in C
(2 answers)
Closed 6 years ago.
Here is one not-so-common way of initializing the array:
int a[3] = {[2] 5, [0] 10, [1] 15};
Used this array in the program,
#include <stdio.h>
int main() {
//code
int a[3] = {[2] 5, [0] 10, [1] 15};
printf("a[0] = %d a[1] = %d a[2] = %d\n", a[0], a[1], a[2]);
return 0;
}
Output:
a[0] = 10 a[1] = 15 a[2] = 5
Online Compiler Link:
http://code.geeksforgeeks.org/4onQAI
So, I have a question:
Is it the correct way to initialize array?
Close. The correct way is as follows:
int a[3] = {[2] = 5, [0] = 10, [1] = 15};
This is a designated initializer, which allows you to initialize specified elements. Any elements not specified are set to 0.
This is specified in section 6.7.9 of the C standard.
The syntax you show is a non-standard extension supported by some compilers, specifically GCC. If you were to compile with -pedantic, you would get the following warning:
warning: obsolete use of designated initializer without ‘=’
Your code snippet uses an obsolete syntax for this designated initializer:
int a[3] = {[2] = 5, [0] = 10, [1] = 15};
An alternative syntax for this that has been obsolete since GCC 2.5 but GCC still accepts is to write ‘[index]’ before the element value, with no ‘=’. (reference)
Omitting = is not standard, and should not be used for new development.
The correct way to use designated initializer is
int a[3] = {[2] = 5, [0] = 10, [1] = 15};
There should be = between the [index] and the value as per the C standard.
The way you are initialising may the some extension.
Grammer for initializations(C11-§6.7.9)
initializer:
assignment-expression
{ initializer-list }
{ initializer-list , }
initializer-list:
designationopt initializer
initializer-list , designationopt initializer
designation:
designator-list =
designator-list:
designator
designator-list designator
designator:
[ constant-expression ]
. identifier

Getting address of rvalue in C99

The following code compiles and works:
#include <stdio.h>
void print(void* x)
{
printf("%d", *(int*)x);
}
int main()
{
print(&((struct { int x, y; }){ .x = 1, .y = 2 })); //outputs 1
return 0;
}
Why compiler allows me to get address of rvalue? Is this defined behaviour?
http://ideone.com/iMwNVr
(struct { int x, y; }){ .x = 1, .y = 2 } is a compound literal, and:
C99 §6.5.2.5 Compound literals
If the type name specifies an array of unknown size, the size is determined by the initializer list as specified in §6.7.8, and the type of the compound literal is that of the completed array type. Otherwise (when the type name specifies an object type), the type of the compound literal is that specified by the type name. In either case, the result is an lvalue.

Resources