0

I can't seem to pin point this problem so I thought I would ask here. I know why this error usually appears, but I can't seem to figure it out this time. Probably something simple I don't know or am missing.

g++  -c -I/usr/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT src/Render.cpp -L/usr/lib/i386-linux-gnu -lSDL -lSDL_image
src/Render.cpp:8:1: error: ‘Render’ does not name a type
src/Render.cpp:13:1: error: ‘Render’ does not name a type
src/Render.cpp:18:14: error: ‘Render’ has not been declared
src/Render.cpp:31:6: error: ‘Render’ has not been declared
make: *** [Render.o] Error 1

Here is my core.cpp, Makefile, and Render.h

Render.cpp

#ifndef _Render_h
#define _Render_h
#include <iostream>
#include "SDL/SDL_image.h"

using namespace std;

Render::Render()
{

}

Render::~Render()
{

}

SDL_Surface* Render::loadImg(string filename)
{
    SDL_Surface* temp = NULL;
    SDL_Surface* optimized = NULL;

    if((temp = IMG_Load(filename.c_str())) != NULL)
    {
        optimized = SDL_DisplayFormat(temp);
        SDL_FreeSurface(temp);
    }
    return optimized;
}

void Render::applySurface(int x, int y, SDL_Surface* source,
        SDL_Surface* destination)
{
    SDL_Rect offset;
    offset.x = x;
    offset.y = y;
    SDL_BlitSurface(source, NULL, destination, &offset);    
}

#endif

core.cpp

#include <iostream>
#include "SDL/SDL.h"
#include "Render.h"

using namespace std;

int main(int argc, char* args[])
{
    string imgGoku = "src/imgs/Goku.bmp";
    string imgVegeta = "src/imgs/Vegeta.png";
    const int SCREEN_WIDTH = 640;
    const int SCREEN_HEIGHT = 480;
    const int SCREEN_BPP = 32;
    SDL_Surface *message = NULL;
    SDL_Surface *background = NULL;
    SDL_Surface *screen = NULL;
    Render rnd;

    if(SDL_Init(SDL_INIT_EVERYTHING) == -1)
    {
        return 1;
    }

    screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT,
            SCREEN_BPP, SDL_SWSURFACE);
    if(screen == NULL)
    {
        return 1;
    }

    SDL_WM_SetCaption("Hello World", NULL);
    rnd.applySurface(10,10,rnd.loadImg(imgGoku),screen);
    if(SDL_Flip(screen) == -1)
    {
        return 1;
    }

    SDL_Delay(2000);
    SDL_FreeSurface(message);
    SDL_FreeSurface(background);
    SDL_Quit();
    return 0;
}

Render.h

#include "SDL/SDL.h"

using namespace std;

class Render{
    public:
        Render();
        ~Render();
        SDL_Surface* loadImg(string filename);
        void applySurface(int x, int y, 
                SDL_Surface* source, 
                SDL_Surface* destination);
};

Makefile

#Game Make file
TARGET = game.exe
OBJS = core.o \
       Render.o \

SDL_CFLAGS := $(shell sdl-config --cflags)
SDL_LDFLAGS := $(shell sdl-config --libs) -lSDL_image
CFLAGS = -Wall
LIBS =
LDFLAGS = 

$(TARGET): $(OBJS)
       g++ $(CFLAGS) $(SDL_CFLAGS) -o $@  $(LDFLAGS) $(OBJS) $(SDL_LDFLAGS) $(LIBS)
%.o: src/%.cpp src/Render.h
       g++  -c $(SDL_CFLAGS) $< $(SDL_LDFLAGS)

.PHONY: clean
clean:
    rm -f $(TARGET) $(OBJS)
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
cgasser
  • 603
  • 2
  • 11
  • 24

2 Answers2

3

You need to include Render.h at the top of Render.cpp

DrYap
  • 6,525
  • 2
  • 31
  • 54
  • Yup. I thought that's what #ifndef and #define did, but guess I understood them or used them wrong. – cgasser Jun 09 '12 at 07:21
3

Yup. I thought that's what #ifndef and #define did, but guess I understood them or used them wrong.

You misunderstood them and you used them wrong.

While adding a #include "Render.h" directive to your Render.cpp file will fix your immediate compilation problem, it does not fix the twin problems of misunderstanding and misuse. There are two other fixes you should make to your code. I'll summarize the corrections you should make and then say why you should do this.

Problem #1: You need to move that #ifndef _Render_h / #define _Render_h pair, and the closing #endif, from the source file to the header.

Problem #2: Remove the leading underscore from the preprocessor symbol _Render_h.

#include guards
Look at almost any system header file and you'll see they follow a very standard layout. The file starts with a header comment that describes the file. Immediately after this are a pair of lines of the form #ifndef _SOME_NAME_H_ and #define _SOME_NAME_H_. The body of the file follows, and the very last thing in the file is a closing #endif. That #ifndef / #define pair is called a #include guard. The closing #endif is always (well, almost always; some of those system headers violate the standard layout) at the very end.

What this does is to protect against the same header from being included multiple times. Suppose you have header files foo.h, bar.h, and baz.h. Suppose both foo.h and bar.h make use of functionality defined in baz.h. Each of these headers should have a #include "baz.h" directive in then, preferably near the top. Now suppose your main.cpp #includes both foo.h and bar.h. If the file baz.h doesn't have a #include guard it will be included twice in your main.cpp. Your main.cpp most likely won't compile.

The solution to this multiple include problem is put a #include guard in the file baz.h. Now the #include "foo.h" in your main.cpp will paste the body of baz.h into your code, but the #include "bar.h" won't because the #include guard in baz.h will make the preprocessor skip over the body of baz.h.

It's a good idea to put a #include guard in every single one of your header files.

#pragma once
There several problems with the concept of a #include guard.

  • The name has to be specified twice, once in the #ifndef directive and again in the #define directive. This is a huge opportunity for Murphy's law to rear it's ugly head. Programmers can and do mistype one or the other of those names.
  • The #endif at the end is another potential source of problems. Some maintenance programmer (maintenance programmers are the bane of a development programmer's existence) is going to see that adding code after the closing #endif will make for a quick and dirty fix to his vexing problem. Maintenance programmers always choose the quickest, dirtiest solution possible. So done.
  • The name has to be unique. Suppose you are just one of many people working on a big project and suppose both you and someone else have a file named Render.h. The two files are in two different directories, so there's no problem with the two files having the same name. A huge problem arises if both files have a #include guard using the preprocessor symbol Render_h.

There's a nice solution to these problems, the #pragma once directive. This pragma, if it works, does exactly what the #include guard is intended to do, but better. There's only one line instead of three, and there's no preprocessor name. The problem is that "if it works". It's a pragma, so not all compilers support it, and some of those that do support it don't do it right.

I tend to use #include guards because of the portability issues with #pragma once. Others use #pragma once because the portability concerns don't apply to their project. Yet others use both mechanisms.

Leading underscores
If you look at a system header file you will see that it is chock full of names with leading underscores. This might give the impression that using leading underscores is the right thing to do. After all, who knows the language better than compiler vendors?

The reason compiler vendors use leading underscores is to avoid collisions with your code. A good compiler vendor uses leading underscores precisely because doing so will keep their names from colliding with your names if you do not use leading underscores in any of your names. You should never use a leading underscore in the name of a class, a global variable, a free function, or a preprocessor symbol. Leading underscores are reserved for use by the compiler.

David Hammen
  • 32,454
  • 9
  • 60
  • 108
  • Thanks, that was really informative and helped me understand that a lot! – cgasser Jun 09 '12 at 10:41
  • Actually, leading underscores _per se_ aren't all reserved (but the see caveat in the following sentence); double underscores (anywhere in a name) and initial underscore plus capital letter are. The caveat is that initial underscores in global scope are reserved. Some of this is surprising, since a lot of code contains things like `typedef struct _Foo { } Foo;`. See http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier for more. – echristopherson Jun 10 '12 at 04:54
  • @echristopherson Yes, there are nuances that do allow the use of a leading underscore in some situations. Do note that the top two responses deal with those nuances the same way I do: Don't. Just never use a leading underscore and you'll be safe (at least with these kinds of collisions). – David Hammen Jun 10 '12 at 05:20