variably modified array at file scope in C - c

I have some code like this:
static int a = 6;
static int b = 3;
static int Hello[a][b] =
{
{ 1,2,3},
{ 1,2,3},
{ 1,2,3},
{ 1,2,3},
{ 1,2,3},
{ 1,2,3}
};
but when I compile it, it says error:
variably modified 'Hello' at file scope
how could this happen? and how could I fix it?

You can not have static array which size is given as a variable
That's why constants should be #defined:
#define a 6
This way preprocessor will replace a with 6, making it valid declaration.

Simple answer variable modified array at file scope is not possible.
Detailed :
make it compile time integral constant expression, since array length must be specified at the compile time.
like this :
#define a 6
#define b 3
Or, follow c99 standard. and compile like for gcc.
gcc -Wall -std=c99 test.c -o test.out
The problem here is variable length array with providing length may not be initialized so you are getting this error.
simply
static int a =6;
static int b =3;
void any_func()
{
int Hello [a][b]; // no need of initialization no static array means no file scope.
}
Now use for loop or any loop to fill the array.
For more info just a DEMO :
#include <stdio.h>
static int a = 6;
int main()
{
int Hello[a]={1,2,3,4,5,6}; // see here initialization of array Hello it's in function
//scope but still error
return 0;
}
root#Omkant:~/c# clang -std=c99 vararr.c -o vararr
vararr.c:8:11: error: variable-sized object may not be initialized
int Hello[a]={1,2,3,4,5,6};
^
1 error generated.
If you remove static and provide initialization then it will generate error as above.
But if you keep static as well as initialization the still will be error.
But if you remove initialization and keep static the below error will come.
error: variable length array declaration not allowed at file scope
static int Hello[a];
^ ~
1 error generated.
So variable length array declaration not allowed at file scope so make it function or block scope inside any function (but remember making it function scope must remove initialization)
NOTE : Since it's C tagged so making a and b as const won't help you but in C++ const will work fine.

When using CLANG/LLVM the following works:
static const int a = 6;
static const int b = 3;
static int Hello[a][b] =
{
{ 1,2,3},
{ 1,2,3},
{ 1,2,3},
{ 1,2,3},
{ 1,2,3},
{ 1,2,3}
};
(To see it in the generated assembly, one needs to use Hello so it will not be optimized out)
However, this will generate an error if C99 mode is selected (-std=c99),
it will only generate a warning (Wgnu-folding-constant) if -pedantic is selected.
GCC does not seem to allow this (const is interpreted as read-only)
See explanation in this thread:
"Initializer element is not constant" error for no reason in Linux GCC, compiling C

Yea, this is annnoying:
const int len = 10;
int stuff[len];
Gives the error. I try to get away from doing #define x, because const int is a better way of declaring a constant, but then you have these cases where const int is not a true constant, even though the compiler knows full well it is.

Related

Initialising a static const variable from a function in c

I have recently run into some trouble while trying to perform the following logic:
static const int size = getSize();
int getSize() {
return 50;
}
The error I have received is initialiser element is not constant
Having read online I understand that this issue is because the compiler evaluates the static const expression at compilation and therefore cannot know what the value is supposed to be.
My question is how do I get around this?
If I have a library that contains many functions but they all require this logic how are they supposed to use it without having to calculate it each time?
And even if they have to, what if the logic itself can change throughout runtime but I only ever want the first value I receive from the function?
Perhaps I should clarify that the logic in getSize is just an example, it could also contain logic that retrieves the file size from a specific file.
Unlike in C++ you cannot initialize global variables with the result of a function in C, but only with real constants known at compile time.
You need to write:
static const int size = 50;
If the constant must be computed by a function you can do this:
Dont declare static const int size = ... anymore, but write this:
int getSize()
{
static int initialized;
static int size;
if (!initialized)
{
size = SomeComplexFunctionOfYours();
initialized = 1;
}
return size;
}
int main(void)
{
...
int somevar = getSize();
...
That way SomeComplexFunctionOfYours() will be called only once upon the first invocation of getSize(). There is a small price to be paid: each time you invoke getSize(), a test needs to be performed.
Or you can initialize it explicitely like this, but then size cannot be const anymore:
static int size;
void InitializeConstants()
{
size = SomeComplexFunctionOfYours();
}
int main(void)
{
InitializeConstants();
...
int somevar = size;
...
The compiler needs to know the value of your constant variable at the compilation time, because its a constant.
Also you can't initialize a variable with a function.
You should do something like this :
#define SIZE 50
static const int size = SIZE;

move Typedef enum array in another function

I want to move the array in another function (type void), to change the value of the array, but every times i have got an error under gcc
I have those following rules:
in this exercise it's forbidden to use global variable,
We want to move the array by reference and not use pointers:
.
#include <stdio.h>
typedef enum {F=0,T=1} Mat;
//==========================//
void unknown(Mat b[][][]){
b[0][0][0]=7;
printf("%d\n",b[0][0][0]);
}
//=========================//
int main(void){
Mat b[2][2][2];
b[0][0][0]=1;
printf("%d\n",b[0][0][0]); //before the unknown
uknown(b);
printf("%d\n",b[0][0][0]); //after unknown
return 0;
}
I have the following error:
test.c:7:18: error: array type has incomplete element type ‘Mat[] {aka
enum []}’ void unknown(Mat b[][][]){
^ test.c: In function ‘main’: test.c:21:9: error: type of formal parameter 1 is incomplete unknown(b);
^
The question is : I need to change the value of the array, not in main, but in the function void unknown, and check in the main (after having change in void unknown values of array Mat b) if this array change this value by reference, what's wrong ? and what do I need to change inside the code ?
(my gcc version: gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609)
You must specify all array dimensions except the first when you pass the array to a function; you may specify the first dimension.
Thus:
#include <stdio.h>
typedef enum { F = 0, T = 1 } Mat;
static void unknown(Mat b[][2][2])
{
b[0][0][0] = 7;
printf("%d\n", b[0][0][0]);
}
int main(void)
{
Mat b[2][2][2];
b[0][0][0] = 1;
printf("%d\n", b[0][0][0]);
unknown(b);
printf("%d\n", b[0][0][0]);
return 0;
}
Output:
1
7
7
You could also write: void unknown(Mat b[2][2][2]).
The static is needed to quell a compiler warning under my default compilation options. Since there isn't any other source file, the function doesn't need to be visible outside this file and can be static. Alternatively, I could declare the function: extern void unknown(Mat b[][2][2]); before defining it — that would also satisfy the options I use. (The extern is optional, but I use it, even though there are others who excoriate the practice; it is symmetric with how global variables need to be declared on those rare occasions when I use one.) I don't make any variable or function visible outside its source file unless there's a compelling reason for it to be visible — not even when it's a single file compilation. If the function should be visible outside the source file, it should be declared in a header that is used both in the source file where the function is defined and in all the source files that use the function. That ensures that the definition and declarations are consistent.

Initialize array after declaring in C

I am trying to do the following but am getting the following error:
"error: expected expression before { token
Test_Stubs.h
#define SIGNATURE 0x78,0x9c
Test.c
#include "Test_Stubs.h"
static unsigned myArray[100];
static void
setup(void)
{
myArray = {SIGNATURE};
}
EDIT
Follow on question:
Is there a way to assign the individual values in the #define to specific indexes of myArray? For instance...
#include "Test_Stubs.h"
static unsigned myArray[100];
static void
setup(void)
{
myArray[0] = SIGNATURE[0]; //0x78
myArray[1] = SIGNATURE[1]; //0x9c
}
Clearly the above code will not code as SIGNATURE is neither an array or pointer.
As per the C syntax rules, you can only initialize an array using a brace enclosed initializer list at the time of definition.
Afterwards, you have to initialize element by element, using a loop, or, if you need to initialize all the elements to the same value, you can consider using memset().
EDIT:
No, as I mentioned in my comments, as per your code snippet, SIGNATURE is neither an array name, nor represent any array type, so you cannot use indexing on that.
However, using compound literal (on and above C99), if you change your #define, then, somehow, you can make this work. See the below code for example,
#include <stdio.h>
#define SIGNATURE ((unsigned [100]){0x78,0x9c})
static unsigned myArray[100];
int main (void)
{
myArray[0] = SIGNATURE[0]; //0x78
myArray[1] = SIGNATURE[1]; //0x9c
return 0;
}
See a LIVE VERSION

multi-dimensioned array initialization using const

This kind of initialization works
int arr[3][4] = { {1,2,3,4}, {1,2,3,4}, {1,2,3,4} } ;
but this one here doesn't
const size_t row_size = 3;
const size_t col_size = 4;
int arr[row_size][col_size] = { {1,2,3,4},{1,2,3,4},{1,2,3,4}};
these codes are in c but after changing the file extension to c++ and re-compiling
it works fine. why such a behavior?
That used to be a problem with C and macros were used to solve such problems. But in C++ if you use "const" keyword then the compiler should automatically replace those values during compile time so there shouldn't be any problem with g++. That code runs perfectly fine when compiled with g++. Maybe you are trying to compile it with gcc (I got the same error with gcc which is as expected).
Actually, having a const-variable doesn't mean it is constant at compile time. For example, I can
void f(int x) {
const int y = x;
int m[y]; // should that work?
}
It won't work in good old C++03, as compiler cannot determine y at compile time. Though it would be possible in C++ soon with the feature called Variable Length Arrays, it seems all you want is plain compile-time constant. Just say it's also static:
static const int size_t row_size = 3;
Since now, you can use it in compile-time.

Initialization of a pointer array

I'm facing a problem initializing an array with pointers to members of a structure. The structure members have to be accessed through a structure pointer. The reason for this is we initialize the pointer at runtime to a memory mapped address location. The following code snippet is an example of the problem;
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
long* lp;
}T;
typedef struct
{
long l;
}F;
F* f;
T t[] =
{
{ &f->l }
};
void init (void)
{
f = (F*) 0x08000100;
}
int main (void)
{
init();
return EXIT_SUCCESS;
}
The compiler output is the following;
gcc -O0 -g3 -Wall -c
-fmessage-length=0 -osrc\Test.o ..\src\Test.c ..\src\Test.c:18:
error: initializer element is not constant
..\src\Test.c:18: error: (near initialization for `t[0].lp')
..\src\Test.c:18: error: initializer element is not constant
..\src\Test.c:18: error: (near initialization for `t[0]')
Build error occurred, build is stopped
The problem here is we initialize the pointer at runtime, the compiler doesn't know where it can find the structure members. We cannot work around the structure pointer as we don't wan't to use the linker script for this.
Any ideas how to get around this one?
T t[] =
{
{ &f->l }
};
The address of an element (e.g. &f->l) is only known at run-time.
Such a value cannot be used for compile-time initialization (which is what's being done here).
The t[] array cannot be filled out until runtime - because the address of F isn't known until runtime.
You could initialize T[] to {NULL} and patch it in post-init.
Another approach is to initialize the members of T to just simply be the offset within the structure, and after you init f, to walk through the array and adjust the pointer locations by adding the address of f. This technique is similar to what is often used in linking.
Something like this:
#define MEMBER_OFFSET_OF(a,b) &(((a*)0)->b)
T t[] =
{
{(long*)MEMBER_OFFSET_OF(F, l)}
};
const int numElementsInT = sizeof(t) / sizeof(t[0]);
void init()
{
f = (F*) 0x08000100;
for (int i= 0; i < numElementsInT; i++)
{
t[i].lp += (unsigned int)f;
}
}
Lets imagine that you could use non-constant data to initialize a global: you still have a huge problem.
When t is initialized, f still has an indeterminate value: this happens before init() executes and assigns your magic address. Because of this, even if you could use &f->l, you'd have to reset all places it's been used, anyway.
Technically speaking for a C90 compiler there is no way around this. For the initialization idiom,
declarator = initialization sequence
the initialization sequence needs to be a constant expression, i.e. one which can be computed at compile-time or at link-time. So,
int a;
int *b[] = { &a };
works, while
void foo() {
int a;
int *b[] = { &a };
}
will not because the address of the automatic a isn't computable before runtime.
If you switch to C99, the latter will work. Your code however still is beyond what a C99 compiler can precompute. If you switch to C++ your code would work, at least Comeau doesn't object.
Edit: of course Roger is correct in that this doesn't solve your problem of having an incorrect dereferencing through a NULL pointer.

Resources