How to use header guards?

Sep 8, 2013 at 10:22am
Hello

I have a header called Constants.h. I want to use it in main.cpp, Ball.cpp and Paddle.cpp. So I added this to Constants.h: #pragma once since I read somewhere that it is supported in MinGW(for versions later than 3). But that's not working. And how do I use header guards to do the same?

So how do I use it to include a single file multiple times?

Thanks
Sep 8, 2013 at 10:25am
closed account (S6k9GNh0)
How do you know it's not working?

Wait, what are you trying to accomplish exactly?
Last edited on Sep 8, 2013 at 10:26am
Sep 8, 2013 at 10:27am
Cause I get the following error:

obj\Debug\main.o ||

In function `ZSt7forwardIRKN2sf6VertexEEOT_RNSt16remove_referenceIS4_E4typeE':

c:\mingw\bin\..\lib\gcc\mingw32\4.7.2\include\c++\mingw32\bits\gthr-default.h|403|multiple definition of `BallSpeed'|

obj\Debug\Ball.o:D:\CodeBlocks\SFML 2.0\Games\Pong_Final\Ball.cpp|7|first defined here|
Last edited on Sep 8, 2013 at 10:27am
Sep 8, 2013 at 10:28am
closed account (S6k9GNh0)
I knew it... show the code!
Sep 8, 2013 at 11:02am
Why not just use the typical means of doing it?

http://en.wikipedia.org/wiki/Include_guard
Sep 8, 2013 at 11:24am
closed account (S6k9GNh0)
There's actually a few good reasons.

http://en.wikipedia.org/wiki/Pragma_once

I use #pragma once myself and just claim any compiler that doesn't allow it isn't supported.
Last edited on Sep 8, 2013 at 11:25am
Sep 8, 2013 at 12:55pm
My codes are quite long, so I am posting only what's relevant.
Here's my Constants.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/****************
*  Constants.h  *
****************/

#ifndef CONSTANTS_H_INCLUDED
#define CONSTANTS_H_INCLUDED


/** Window related constants **/
const int WINDOW_WIDTH = 800;           // specify window width
const int WINDOW_HEIGHT = 600;          // specify window height
const int WINDOW_BPP = 32;              // specify window bits per pixel
const char *WINDOW_CAPTION = "Pong";    // specify window caption


/** Ball related constants **/
sf::Vector2<float> BallSpeed(0.4, 0.4);


#endif // CONSTANTS_H_INCLUDED 


Here's Ball.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include "Ball.h"
#include "Constants.h"

Ball::Ball()
{
    //ctor
}

Ball::Ball(float RADIUS, sf::Color COLOR, const char *BUFFER_NAME)
{
    ballObject.setRadius(RADIUS);
    ballObject.setFillColor(COLOR);

    paddleHit.loadFromFile(BUFFER_NAME);
    Sound_PaddleHit.setBuffer(paddleHit);
}

void Ball::Init(sf::Vector2f POSITION)
{
    ballObject.setPosition(POSITION);
    currentSpeed = BallSpeed;
}

void Ball::deflectX()
{
    currentSpeed.x = -currentSpeed.x;
}

void Ball::deflectY()
{
    currentSpeed.y = -currentSpeed.y;
}

void Ball::accelerate(Paddle PLAYER)
{
    currentSpeed.y = (ballObject.getGlobalBounds().top
                        + ballObject.getGlobalBounds().height / 2
                            - PLAYER.getRect().top
                                - PLAYER.getRect().height / 2) / 100;
}

void Ball::stopMoving()
{
    currentSpeed = sf::Vector2<float>(0.0f, 0.0f);
}
void Ball::resetSpeed()
{
    currentSpeed = BallSpeed;
}

void Ball::playHitSound()
{
    Sound_PaddleHit.play();
}

bool Ball::isColliding(sf::RectangleShape RECTANGLE)
{
    if(ballObject.getGlobalBounds().intersects(RECTANGLE.getGlobalBounds()))
        return true;
    return false;
}

bool Ball::isColliding(sf::FloatRect RECT)
{
    if(ballObject.getGlobalBounds().intersects(RECT))
        return true;
    return false;
}

sf::Vector2f Ball::getBallPosition()
{
    return ballObject.getPosition();
}

float Ball::getBallRadius()
{
    return ballObject.getRadius();
}

void Ball::move()
{
    ballObject.move(currentSpeed.x, currentSpeed.y);
}

void Ball::update(sf::RenderWindow &WINDOW)
{
    WINDOW.draw(ballObject);
}

Ball::~Ball()
{
    //dtor
}


And here's a part of main.cpp:
1
2
#include "Ball.h"
#include "Constants.h" 


But still I am getting the same error(already mentioned in one of the above posts, number three to be precise).
Last edited on Sep 8, 2013 at 12:56pm
Sep 8, 2013 at 1:09pm
Both traditional header guards and #pragma once accomplish the same thing, which is to prevent including the same declarations multiple times in the same module.

However, neither will protect you from including the same definitions in multiple modules, which is what you've done.

Lines 10-17 in constants.h are defining variables. Therefore, if you include constants.h in multiple modules, you will have multiple definitions of these variables at link time, which is what the linker is complining about.

You should never define variables in a header file.
What you should do is declare the variables in the header.

In constants.h:
1
2
3
#pragma once 
extern const int WINDOW_WIDTH; 
.. etc 


Then in one and only one of your .cpp files:
1
2
 
const int WINDOW_WIDTH = 800;           // specify window width 

Last edited on Sep 8, 2013 at 1:11pm
Sep 8, 2013 at 8:33pm
In C++ consts have internal linkage by default, so it's OK to have then defined in the header. In fact, this style makes it easier for the compiler to inline the value than when you declare then with extern in the header and then define them in a source file.

(If you're sharing the header with C code, then what you need to add the static keyword to all the consts. You can use the static keyword with C++, but it's not needed.)

So, these are fine

1
2
3
const int WINDOW_WIDTH = 800;           // specify window width
const int WINDOW_HEIGHT = 600;          // specify window height
const int WINDOW_BPP = 32;              // specify window bits per pixel 


But const char * isn't const: it's a non-const pointer (to a const string). If you want it to be totally const then you need to make the pointer const, too.

char const * const WINDOW_CAPTION = "Pong";

now it's actually a const (and has internal linkage like the int consts)

And if you make BallSpeed const as well, then you don't need to use extern, etc.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/****************
*  Constants.h  *
****************/

#ifndef CONSTANTS_H_INCLUDED
#define CONSTANTS_H_INCLUDED


/** Window related constants **/
const int WINDOW_WIDTH = 800;           // specify window width
const int WINDOW_HEIGHT = 600;          // specify window height
const int WINDOW_BPP = 32;              // specify window bits per pixel
char const * const WINDOW_CAPTION = "Pong";    // specify window caption (now really const)


/** Ball related constants **/
const sf::Vector2<float> BallSpeed(0.4, 0.4); // it is supposed to be a constant?


#endif // CONSTANTS_H_INCLUDED  


Andy
Last edited on Sep 8, 2013 at 8:37pm
Sep 12, 2013 at 12:11pm
@Andy


Thanks, now it works. So, I'd have to define everything(variables etc.) as constants to use it the way I am using? And is their any alternative to declaring everything as constants?

Thanks
Sep 12, 2013 at 12:40pm
is their any alternative to declaring everything as constants?

You can declare variables with external linkage.

In someheader.h
1
2
 
extern sf::Vector2<float> SomeVector;  // declaration visible to all modules that include someheader.h 


In one and only one .cpp file, define the vector.
1
2
3
4
 
#include "someheader.h"
...
sf::Vector2<float> SomeVector;  // Can be initialized here if needed  


This makes SomeVector global across all modules that include someheader.h which is a generally a poor practive, but sometimes it is appropriate.

Thanks to Andy for the clarification on internal linkage of consts.


Topic archived. No new replies allowed.