Define global variable to initiate struct array - c

I'm trying to use global variables to store 3 values from a file. When I run my project this is the error I get:
error: variably modified ‘pkt’ at file scope
error: variably modified ‘num’ at file scope
Here is my code:
config.h
#ifndef READCONFIG_CONFIG_H
#define READCONFIG_CONFIG_H
#include <stdio.h>
#define PATH "src/transferConfig.txt"
extern unsigned long int TIMEOUT_PKT;
extern int START_BUFFER_SIZE;
extern float PROBLOSS;
int getConfig(){
FILE *fp;
int n;
float p;
unsigned long int t;
if((fp = fopen(PATH,"rt")) != NULL) {
fscanf(fp, "N=%d\n p=%f\n T=%ld\n", &n, &p, &t);
fclose(fp);
TIMEOUT_PKT = t;
START_BUFFER_SIZE = n;
PROBLOSS = p;
}else{
TIMEOUT_PKT = 3000000;
START_BUFFER_SIZE = 15;
PROBLOSS = 0;
}
}
#endif //READCONFIG_CONFIG_H
window.h
typedef struct window{
packet* pkt[START_BUFFER_SIZE];
long num[START_BUFFER_SIZE];
}window
Error during the build
error: variably modified ‘pkt’ at file scope
error: variably modified ‘num’ at file scope
How can I fix this error?

START_BUFFER_SIZE is not known at the compile time, and it's not constant as you are able to assign a value to it. Variable size arrays require dynamic memory allocation. You need to know your array size in compile time to be able to use a static array.

Related

How to share global array between c files

I am trying to share a global array between two files as below:
main.c:
#include <stdio.h>
#include "another.h"
int n=10;
int a[n];
void main(){
printf("Enter value:\n");
scanf("%d",&a[0]);
display();
}
another.h:
#include <stdio.h>
extern int n;
extern int a[n];
void display(){
printf("%d",a[0]);
return;
}
However, I am getting the following error:
variable modified 'a' at file scope
I'm not able to understand why I'm getting this error. Does anyone have an explanation?
The following appears to be an attempt at creating a variable length array. But regardless what it is actually, the 2nd of the following two lines is not legal:
extern int n;
extern int a[n];
n is not yet defined at the time it is used to create a.
In case you were thinking to create a VLA...
by definition VLAs are only created with automatic storage duration on the stack. This makes them unusable for use as extern or for any type of globally scoped variable.
However you can declare the size variable as an extern in a header file so that it is project global for any source file that includes that file, and once it is defined it can be used to size any array within project scope:
<some.h>
extern size_t array_size;
extern int gArray[100];
<some.c>
#include "some.h"
...
size_t array_size = 20;
int gArray[100] = {0};//Not a VLA
...
int main(void)
{
int array[array_size] = {0};
for(int i=0;i<sizeof(gArray);i++
{
//populate each element of gArray here
}
...
<someother.c>
#include "some.h"
int otherFunc(void)
{
//gArray is visible here just as it is in main(), with exactly the same values.
int local array[array_size] = {gArray[0],gArray[1],gArray[2],...,gArray[19]};
...

Is variable declaration necessary in C?

See the comments to see what is being referred as declaration.
If the whole variable declaration part was missing, what would be the problem?
Appears that variable definition and initialization either simultaneously or separately like in the example would suffice.
#include <stdio.h>
// Variable declaration:
extern int a, b;
extern int c;
extern float f;
int main () {
/* variable definition: */
int a, b;
int c;
float f;
/* actual initialization */
a = 10;
b = 20;
c = a + b;
printf("value of c : %d \n", c);
f = 70.0/3.0;
printf("value of f : %f \n", f);
return 0;
}
If the declaration was missing then it would create no problem in main function since the locally defined variables i.e. a,b,c,f will be used in the functionality of main till its scope ends.
The declaration merely tells that the definition lies elsewhere (in some other .c file) or the definition lies after the function main in the same .c file.
There will be no problem here if the mentioned declaration is missing.
// Variable declaration:
extern int a, b;
extern int c;
extern float f;
This tells the compiler that these variables are defined somewhere else(in another file).
/* variable definition: */
int a, b;
int c;
float f;
This is where you define variables but they are not the same as the external variables you declared since they are in the inner scope of the main function.
The scope is the place where variables live. extern keyword notes that the scope is global.
You can define variables with the same name in an inner scope and access only them as you did in the main function but it's not a good practice.
void foo()
{
int a = 5;
printf("%d\n", a); // 5
// Creating an inner scope
{
int a = 20;
printf("%d\n", a); // 20
}
printf("%d\n", a); // 5
}
The correct way to use the extern keyword with variables is like this.
//h1.h
extern int global_var; // Declaration of the variable
//c1.c
#include h1.h
int global_var = 0; // Definition of the global var. Memory is allocated here.
//main.c
#include h1.h
int main()
{
printf("global var value is %d\n", global_var); // use of the var defined and
// initialized in c1.c
return 0;
}
This program will print 0 since the variable is defined and initialized in c1.c.
Extern extends the visibility of the C variables and C functions. so that lets the compiler know that there is another place that those vars are declared and memory was allocated for them elsewhere.
for example in another c file.
if you compile a c file containing a global var for example:
int c = 5;
and you create a function on you c file that uses this c var, for example:
int someFunc(void){
return c;}
if you run someFunc in your main and print its return value, you will get 5. but you must compile both c files together.
in your program, you only use the locally allocated var declared in your main function.
When it comes to simple variables, there is really no difference between the declaration and definition. There is a difference when it comes to structs and functions. Here is an example:
// Declarations
struct myStruct;
int foo();
int main()
{
...
}
// Definitions
struct myStruct {
int a, b;
};
int foo() {
return 42;
}
In your case, you are hiding the previous declarations so that they are not accessible before the end of the scope. This is commonly called shadowing. It's basically the same thing as this:
int main()
{
int i=0;
printf("i: %d\n", i);
{
int i=42; // Now the previous i is inaccessible within this scope
printf("i: %d\n", i);
}
// And now it is accessible again
printf("i: %d\n", i);
}

Local variable and static variables

I just want to understand the difference in RAM allocation.
Why if i define a variable before function i have a RAM overflow and when i define it inside a function it is ok?
For example:
/*RAM OK*/
void Record(int16_t* current, int i,int n)
{
float Arr[NLOG2] = {0};
for(i=0;i<n;i++)
Arr[i]=current[i*5];
}
/*RAM OVERFLOW*/
static float Arr[NLOG2] = {0};
void Record(int16_t* current, int i,int n)
{
for(i=0;i<n;i++)
Arr[i]=current[i*5];
}
This is the message:
unable to allocate space for sections/blocks with a total estimated
minimum size of 0x330b bytes (max align 0x8) in
<[0x200000c8-0x200031ff]> (total uncommitted space 0x2f38).
The difference is that in the first case, Arr is declared on the stack; until the function is called, that array doesn't exist. The generated binary contains code for creating the array, but the array itself isn't in the binary.
In the second case, however, Arr is declared outside of any function (aka at file scope). Therefore, it always exists, and is stored in the binary. Because you appear to be working on an embedded platform, this otherwise insignificant difference causes your "RAM overflow" error.
In the 2nd case, the array is allocated when the application starts. It remains in the memory until the app quits.
In the 1st case, the array is only allocated when function void Record(int16_t* current, int i,int n) is called. The array is gone after the function finishes its execution.
static keyword doesn't have any impact if you have only a single compilation unit (.o file).
Global variables (not static) are there when you create the .o file available to the linker for use in other files. Therefore, if you have two files like this, you get name collision on a:
a.c:
#include <stdio.h>
int a;
int compute(void);
int main()
{
a = 1;
printf("%d %d\n", a, compute());
return 0;
}
b.c:
int a;
int compute(void)
{
a = 0;
return a;
}
because the linker doesn't know which of the global as to use.
However, when you define static globals, you are telling the compiler to keep the variable only for that file and don't let the linker know about it. So if you add static (in the definition of a) to the two sample codes I wrote, you won't get name collisions simply because the linker doesn't even know there is an a in either of the files:
a.c:
#include <stdio.h>
static int a;
int compute(void);
int main()
{
a = 1;
printf("%d %d\n", a, compute());
return 0;
}
b.c:
static int a;
int compute(void)
{
a = 0;
return a;
}
This means that each file works with its own a without knowing about the other ones.

Changing variable (array of structs) from global to local (simple C program)

This is my code that I am compiling in C. Currently I have a global variable 'code' that is an array of structs(struct instruction). I've been trying to instead make this a local variable in main and pass it as a parameter. Also I believe this means I will need to have read file return a struct instruction*. I would greatly appreciate it if someone could explain, or show me how to properly use 'code' as a local variable. Also I am interested in what makes local variables better or more efficient than global variables. Thanks!
#include<stdio.h>
#include <stdlib.h>
typedef struct instruction{
int op; //opcode
int l; // L
int m; // M
} instr;
FILE * ifp; //input file pointer
FILE * ofp; //output file pointer
instr code[501];
void read_file(instr code[]);
char* lookup_OP(int OP);
void print_program(instr code[]);
void print_input_list(instr code[]);
int main(){
read_file(code);
print_input_list(code);//used for debugging
print_program(code);
}
void read_file(instr code[]){
int i = 0;
ifp = fopen("input.txt", "r");
while(!feof(ifp)){
fscanf(ifp,"%d%d%d",&code[i].op, &code[i].l, &code[i].m);
i++;
}
code[i].op = -1; //identifies the end of the code in the array
fclose(ifp);
}
You have to move your declarations inside the functions that need them:
#include <stdio.h>
#include <stdlib.h>
typedef struct instruction{
int op; //opcode
int l; // L
int m; // M
} instr;
void read_file(instr code[]);
char* lookup_OP(int OP);
void print_program(instr code[]);
void print_input_list(instr code[]);
int main(){
instr code[501]; // code[] declaration moved HERE!!!!
read_file(code);
print_input_list(code);//used for debugging
print_program(code);
}
void read_file(instr code[]){
int i = 0;
FILE * ifp; //ifp FILE* declaration moved HERE!!!!
ifp = fopen("input.txt", "r");
while(!feof(ifp)){
fscanf(ifp,"%d%d%d",&code[i].op, &code[i].l, &code[i].m);
i++;
}
code[i].op = -1; //identifies the end of the code in the array
fclose(ifp);
}
I've moved ifp declaration inside readfile() and code inside main().
The variable ofp has been removed, because it is not used.
If you are using ofp inside another function, declare it there.
Simple enough.
No real change in efficiency as you have currently coded it.
The only change is the storage for code will be from the stack
int main(){
instr code[501];
read_file(code);
print_input_list(code);//used for debugging
print_program(code);
}
I'll go ahead and try to answer the last part of the question:
Also I am interested in what makes local variables better or more
efficient than global variables.
There are a few differences between Local and Global defined variables.
Initialization. Global variables are always initialized to zero, where as local variables will have an unspecified/indeterminate value prior to being assigned. They don't have to be initialized as stated previously.
Scope. Global variables can be accessed by any function in the file (and even out of the file by using extern, without passing a reference to it. So, in your example you didn't need to pass a reference to code to the functions. The functions could have just accessed it normally. Local variables are defined only in the current block.
For example:
int main() {
int j = 0;
{
int i = 0;
printf("%d %d",i,j); /* i and j are visible here */
}
printf("%d %d",i,j); /* only j is visible here */
}
This would not compile, because i is no longer visible in the main code block. Things could get tricky when you have global variables named the same as local variables. It's allowed but not recommended.
Edit: Local variable initialization changes based on comments. Changed text in italics above.

C typedef in header file variably modified at file scope

I need to include some typedef definition in two source files:
typedef double mat[MATSIZE][MATSIZE] ;
so I created def.h which includes:
#ifndef DEF_H
#define DEF_H
typedef double mat[MATSIZE][MATSIZE] ;
#endif
and in both .c files I included it by:
in the first file processed:
#define MATSIZE 4
#include "def.h"
in the second .c file:
extern int MATSIZE;
#include "def.h"
But I get
error: variably modified ‘mat’ at file scope
What did I do wrong?
The concept of Variable Length Arrays (VLAs) is "new" to C99.
Before C99 you could only use real constants for specifying sizes of arrays. The following code was illegal either in block scope or file scope.
const int size = 42; /* size is not a real constant */
int boo[size];
C99 introduced VLA for block scope. The example code above is legal C99, provided it happens in block scope. Your definition is at file scope and therefore invalid.
Also it is a really bad bad idea to have the same typedef refer to two different types.
When arrays are defined outside a block (at file scope or global scope), the size must be known at compile time. That means that the each dimension on the array must be a constant integral value (or, for the first dimension, it could be implied by the initializer for the array).
If you used a C89 compiler, you might get a message about non-constant array dimensions. GCC 4.6.1 gives the 'variably modified mat at file scope' message.
C99 added Variable Length Arrays to the repertoire, but they can only appear inside a block or an argument list, where the size can be determined at runtime.
So, in a function, you could legitimately write:
extern int MATSIZE;
extern void func(void);
void func(void)
{
typedef double mat[MATSIZE][MATSIZE];
// ...
}
(The function declaration is needed to avoid the warnings like:
warning: no previous prototype for ‘func’ [-Wmissing-prototypes]
since I habitually compile with -Wmissing-prototypes.)
The other issue is that in one file, MATSIZE is a compile-time (#defined) constant; in the other, there is apparently an integer variable MATSIZE. These are completely unrelated. The types therefore are different.
typdef is block scoped
wildplasser is concerned about whether typedef is block-scoped or global. It is block-scoped, as this otherwise execrable code demonstrates:
#include <stdio.h>
static void function(void)
{
typedef int i;
i j = 1;
printf("j = %d\n", j);
{
typedef double i;
i j = 2.1;
printf("j = %f\n", j);
}
{
typedef char i[12];
i j = "this works";
printf("j = %s\n", j);
}
}
int main(void)
{
function();
return(0);
}
If that was present to me for code review, it would be summarily rejected. However, it amply demonstrates a point.
MATSIZE is not known. Which is why you are getting this issue.
#ifndef DEF_H
#define DEF_H
#define MATSIZE 100 /* or whatever */
typedef double mat[MATSIZE][MATSIZE]
#endif

Resources