-1

In my project in CLion, I have some headers. One of them is constants.h in which I put all my constants. Now, I want to use this header in main.c and view.h. view.c is another source file which is associated with view.h. Whenever I use it, it gives error because of redefinition of constants. I also used:

//constants.h
#ifndef PROJECT_CONSTANTS_H
#define PROJECT_CONSTANTS_H
# define pi 3.14159265359
# define degToRad (2.000*pi)/180.000

//GAME GRAPHICS CONSTANTS
const int TANK_RADIUS = 15;
const int CANNON_LENGTH = TANK_RADIUS;
const int BULLET_RADIUS = 4;
const int BULLET_SPAWN_POS = TANK_RADIUS+BULLET_RADIUS;
//const int tank_width = 10;
//const int tank_height = 20;
const int WIDTH = 800;
const int HEIGHT = 600;

//GAME LOGICAL CONSTANTS
const int step = 5;
const double angleStep = 4.5;
const int bulletSpeed = 8;
#define maxBulletPerTank  10
#endif

//main.c includes
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <SDL.h>
#include <SDL2_gfxPrimitives.h>
#include "structs.h"


#include "view.h"

//view.h
#ifndef PROJECT_VIEW_H
#define PROJECT_VIEW_H

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <SDL.h>
#include <SDL2_gfxPrimitives.h>
#include "constants.h"


SDL_Renderer* init_windows(int width , int height);

#endif

//view.c

#include "view.h"
SDL_Renderer* init_windows(int width , int height)
{
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Window* window = SDL_CreateWindow("workshop", 100, 120, width, height, SDL_WINDOW_OPENGL);
    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    return renderer;
}

At the first part of constants.h but including it in both main.c and view.h gives me the error. Is there anyway to solve this? Note that if I don't include it in view.h, it don't recognize some parts that use constants defined in constants.h. I need to use this constants in several other .h files.

at top of main.c and view.h I have: #include<constants.h> and I have #include<view.h> at top of view.c. view.his also included at top of main.c

One of the Errors:

CMakeFiles\project_name.dir/objects.a(view.c.obj):[address]/constants.h:26: multiple definition of `step':
CMakeFiles\project_name.dir/objects.a(main.c.obj):[address]/constants.h:23: first defined here

I am new to Standard Programming and don't know how to handle this.

amir na
  • 217
  • 1
  • 13
  • 1
    Please provide a [mcve] – UnholySheep Dec 22 '18 at 15:40
  • Can you give us your error message? – NaWeeD Dec 22 '18 at 15:41
  • @NaWeeD I added the constants.h code and one of the errors. – amir na Dec 22 '18 at 15:46
  • 1
    `constants.h` by itself looks alright, and has the proper `#ifndef/#define` boilerplate to work. Is the same `#ifndef/#define` setup in `view.h` as well? How do the files import each otheR? – Horia Coman Dec 22 '18 at 15:48
  • @HoriaComan The #ifndef for view.h is `#ifndef PROJECT_VIEW_H`. and the other are also like this but with PROJECT_VIEW_H name. I added how they include each other in paragraph before errors. – amir na Dec 22 '18 at 15:51
  • @amirna post all of code files – EsmaeelE Dec 22 '18 at 15:52
  • 1
    Is `step` being declared elsewhere in `view.c`? If the problem was with the include as a whole the error should be about `TANK_RADIUS` which is the first definition in it, not `step`. The fact it only fails for `step` raises questions. – Havenard Dec 22 '18 at 15:53
  • Also the proper way to make a global variable that is shared between `.c` files is to make it an `extern`. In this case it wont matter because they are all `const` but you probably should do it anyway for transparency. – Havenard Dec 22 '18 at 15:55
  • Why don't you use classic `#define`? – linuxfan says Reinstate Monica Dec 22 '18 at 16:00
  • @Havenard. It is one of the errors and the first one is TANK_RADIUS. it actually gives error for all the constants and not just that. I copied just one of them to show what is the error. – amir na Dec 22 '18 at 16:00
  • Show us the real `constant.h` file, not a stripped version – Amadeus Dec 22 '18 at 16:00
  • Well, in this case the only thing I know about the problem is that it is not in the code you showed us. – Havenard Dec 22 '18 at 16:02
  • @Amadeus I added all the related headers exact code to the question body. the main.c is more than 300 lines and I just added the include parts. – amir na Dec 22 '18 at 16:04
  • @Havenard I added main.c includes and view.h ,view.c and constants.h to the question. as I said in the above comment, the main.c is more that 300 lines and I just added the include parts. – amir na Dec 22 '18 at 16:06
  • Instead of `const`, try `static const` – Amadeus Dec 22 '18 at 16:07
  • I'd try `extern` just to see what happens. At any rate, those don't even need to be variables, you could make them defines. – Havenard Dec 22 '18 at 16:07
  • @Amadeus Static const worked well but can you describe how it works? – amir na Dec 22 '18 at 16:11
  • @Havenard yes I can use define but the problem is that I know that for the other parts of the problem that I didn't code yet, I might need to use variables (not constants) this way and in this case, they may lead to errors. – amir na Dec 22 '18 at 16:13
  • There are a lot of resources on internet about this matter, you can look, for example, here: https://stackoverflow.com/questions/13185751/what-is-the-difference-between-static-const-and-const or here https://stackoverflow.com/questions/23652665/static-const-vs-extern-const – Amadeus Dec 22 '18 at 16:16
  • > "might need to use variables"... you should not declare variables in header files anyway. BTW: what is the compiler you use? – linuxfan says Reinstate Monica Dec 22 '18 at 16:17
  • @linuxfan mingw32 – amir na Dec 22 '18 at 16:23
  • Quick try: change all the variables to `#define ...` (or just one). I don't see anything wrong with your code. – linuxfan says Reinstate Monica Dec 22 '18 at 16:26
  • I did not understand your problem because I am unable to replicate it. But I think that you are trying to include same header file in multiple .c files probably because it contains shared variables. There is a work around for it. You declare all those variables/constants in constant.h as [extern](https://stackoverflow.com/questions/1433204/how-do-i-use-extern-to-share-variables-between-source-files). and define them in one of your .c file. – rsonx Dec 22 '18 at 17:48

1 Answers1

0

The problem is that your header doesn't define constants, it defines (read-only) variables. You get an error because #include copies the contents of the header into each source file that includes it, so every source file tries to define those global variables.

The usual solution when you want global variables is to only put declarations in the header file:

// constants.h
extern const int step;
extern const double angleStep;

The actual variable definitions go in (one) source file:

// constants.c
#include "constants.h"
const int step = 5;
const double angleStep = 4.5;

But note that these are not constants:

switch (...) {
    case step:  // Error: case label must be a constant
        ...
}

If you want actual constants, you should use macros instead:

// constants.h
#define STEP 5
#define ANGLE_STEP 4.5

Then you don't need a separate .c file either.

For integer constants only, there's a workaround involving enums:

// constants.h
enum { step = 5 };

This creates an actual integer constant called step; unfortunately this technique cannot be used with floating-point numbers.

melpomene
  • 84,125
  • 8
  • 85
  • 148