1

I am writing a SDL program in C and I am using raycastlib. I set a global variable in a header file. I change it in main() and then call another function. This function uses the old value of the variable.

I have tried giving the new variable as an argument to the function, but that function called another function and it broke again. I don't want to add this as an argument to literally all functions in the header (yes this function uses almost all functions).

void draw() 
{
  RCL_RayConstraints c;

  c.maxHits = 32;
  c.maxSteps = 32;

  RCL_renderComplex(camera,floorHeightAt,ceilingHeightAt,textureA
t,c); 
}

This is the function as it is. The code is based on the example from raycastlib. It just tries to procedurelly generate the world (levelFloor in the code).

If this is not possible I will need to set the variable from the start (that is okay, the map doesn't change) but I will need to find a way to pass an array from a generating function to a variable without the main function to start the function.

The header file:

#define MAZE_WIDTH 25
#define MAZE_HEIGHT 25

int levelFloor[MAZE_WIDTH * MAZE_HEIGHT]; /* THIS VARIABLE IS THE PROBLEM */

static void shuffle(int *array, size_t n)
{
/* stuff */
/* returns nothing (but changes levelFloor) */
}

The part of main loop that uses these:

/* stuff */
 
#define STARTX (MAZE_WIDTH - (MAZE_WIDTH % 4))/2 
#define STARTY (MAZE_HEIGHT - (MAZE_HEIGHT % 4))/2

  MAZE_Recurse(STARTX,STARTY,levelFloor);
 
#undef STARTX 
#undef STARTY

/* checked if it is changed here. it is. */

and

draw(levelFloor) /* I also tried changing the function and passing levelFloor as an argument which worked but didn't effect the other called function */

the draw() function:

void draw(int levelFloor[]) /* originally I didn't pass levelFloor as an argument */
{
  RCL_RayConstraints c;

  c.maxHits = 32;
  c.maxSteps = 32;
  RCL_renderComplex(camera,floorHeightAt,ceilingHeightAt,textureA
t,c); 
}

RCL_RenderComplex comes from raycastlib.

To abstract the code is like this:

/*main.c*/
#include "xar.h"
#include "bar.h"

void foo()
{
  bar();
}
int main()
{
  xar();
  foo();
}
/*bar.h*/
void bar()
{
  stuff();
}
/*xar.h*/
int var[];

void xar()
{
  var = 1;
  return;
}

Thanks.

EDIT: I think I am going to rewrite the program.

  • 1
    What global variable? Post the relevant code including variable declarations. – Lundin Mar 20 '23 at 07:44
  • Welcome to Stack Overflow. Please read [the help pages](http://stackoverflow.com/help), take the SO [tour], read [ask], as well as [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). Then please create a [mre], and [edit] your question to show it together with a detailed description of the problems you have. If you have build-errors, then copy-paste the full and complete build log (as text) into the question, and add comment in the code where you get the errors. – Some programmer dude Mar 20 '23 at 07:45
  • Thanks for the feedback, it doesn't give compiler errors. I will edit the question to add the full code. – Macintosh3D Mar 20 '23 at 07:49
  • You have mentioned a global variable, a header file, and something you tried but failed, but have shown none of that. Basically the part that is wrong you have not shown. The symptoms you describe could have multiple causes, we cannot guess. All that said, you probably already have a failed design if you are resorting to globals, and you certainly have broken code if you have variables (rather than simply declarations) in header files. – Clifford Mar 20 '23 at 07:50
  • "I set a global variable in a header file." Sounds wrong... It can be done in a header file but that's not the usual way as it gives a number of problems. Put it in a c-file and put an extern declaration in the header – Support Ukraine Mar 20 '23 at 07:52
  • In the first part of this answer https://stackoverflow.com/a/1433387/4386427 you can find help. – Support Ukraine Mar 20 '23 at 08:07
  • or perhaps https://stackoverflow.com/questions/68446686/correct-use-of-extern-when-using-global-variables-imported-from-standard-library – Support Ukraine Mar 20 '23 at 08:08
  • thanks, I didn't know about extern. I don't remember about it in EssentialC. I think I need to read the whole C23 spec. – Macintosh3D Mar 20 '23 at 08:12
  • @Macintosh3D Reading the specification isn't needed. Any decent beginner book should have information about external variable declarations versus variable definitions. And there are many tutorials online about how to build projects using multiple source and header files. – Some programmer dude Mar 20 '23 at 08:47

1 Answers1

2

The main issue seems to be that you declare variables/arrays in headers. That is bad practice, since it means that the variable will only be available to a certain translation unit. That is:

  • In case foo.h contains the array and foo.c includes foo.h, then foo.h + foo.c forms a translation unit and the array will only exist there.
  • If another file bar.c includes foo.h, then a different array with the same name will exist in the translation unit foo.h + bar.c.
  • If you are lucky you get linker errors at that point.

The work-around is to declare the array as extern int array [n]; in the header file foo.h and in the file foo.c only, define the variable int array[n] = { ... };.

However that using "globals" with extern a poor design as well, since it exposes a variable to multiple files. This is called "tight coupling" or sometimes "spaghetti programming", where a poor design forces unrelated parts of the program to depend on each other. Change the variable in one file and poof: some unrelated file also using that variable suddenly stops working. Meaning you'd have to track down all uses of the variable to solve the bug. Also these are generally not safe for multi-threading.

A better solution is to share data between unrelated files through so-called "setter/getter" functions. Then it becomes clear who the data belongs to.

Lundin
  • 195,001
  • 40
  • 254
  • 396