I have been hammering at this for the past 2 days and i've already tried every single solution on the internet, so here goes.
I have a problem with undefined references. I am doing a project to compare 3 algorithms and i have compartmentalized them into 3 different sets of cpp files. I am using Dev C++ with gcc 4.9.2.6 as my compiler. I know it is a linker error, but all my solutions are not working and i can't seem to identify it.
My main file is
#include <iostream>
#include <stdio.h>
#include <string>
#include <fstream>
#include <time.h>
#include "SDL.h"
#include "bitmap_image.hpp" //ext
#include "Bresenham.hpp"
#include "XiaolinWu.hpp"
#include "GuptaSproull.hpp"
void GenerateBMPBlank(int xsize,int ysize,std::string fileid);
void BresenhamTest(int xsize,int ysize, std::string TestDataFile);
void XiaolinWuTest(int xsize,int ysize, std::string TestDataFile);
void GuptaSproullTest(int xsize, int ysize, std::string TestDataFile);
void executeTest(int xsize,int ysize, std::string TestDataFile); //resulting BMP file generated will have the format "x_y_algorithmName.bmp"
int main()
{
short x,y;
std::string TestFileLocation;
std::cout << "Please indicate file path of Test Data textfile"<< std::endl;
std::cin>>TestFileLocation;
std::cout << "Please indicate file dimensions" << std::endl;
std::cin>> x >> y;
executeTest(x,y, TestFileLocation);
std::cout<< "Procedure executed"<< std::endl;
std::cin.get();
return 0;
}
void GenerateBMPBlank(int xsize,int ysize,std::string fileid) //uses external library http://partow.net/programming/bitmap/ to generate a blank white bmp file
{
bitmap_image blankBMP(xsize,ysize); //creates bitmap image
blankBMP.set_all_channels(255,255,255); //sets entire image to be completely white
blankBMP.save_image(fileid);
} //tested
void executeTest(int xsize,int ysize, std::string TestDataFile)
{
SDL_Init( SDL_INIT_EVERYTHING );
std::cout<<"Beginning test of data set from "+TestDataFile<<std::endl;
std::cout<<"Now executing Bresenham's algorithm"<<std::endl;
BresenhamTest(xsize,ysize, TestDataFile);
std::cout<<"Now executing Xiaolin Wu's algorithm"<<std::endl;
XiaolinWuTest(xsize,ysize,TestDataFile);
std::cout<<"Now executing Gupta Sproull 's algorithm"<<std::endl;
GuptaSproullTest(xsize,ysize,TestDataFile);
SDL_Quit();
}
void BresenhamTest(int xsize,int ysize, std::string TestDataFile)
{
std::string ResultName= std::to_string(xsize) + "_" + std::to_string(ysize) + "_Bresenham.bmp";
GenerateBMPBlank(xsize,ysize,ResultName);
clock_t tStart = clock();
Bresenham b(ResultName,TestDataFile);
printf("Time taken for Bresenham: %.4fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);
}
void XiaolinWuTest(int xsize,int ysize, std::string TestDataFile)
{
std::string ResultName= std::to_string(xsize) + "_" + std::to_string(ysize) + "_XiaolinWu.bmp";
GenerateBMPBlank(xsize,ysize,ResultName);
clock_t tStart = clock();
XiaolinWu w(ResultName,TestDataFile);
printf("Time taken for XiaolinWu: %.4fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);
}
void GuptaSproullTest(int xsize,int ysize, std::string TestDataFile)
{
std::string ResultName= std::to_string(xsize) + "_" + std::to_string(ysize) + "_GuptaSproull.bmp";
GenerateBMPBlank(xsize,ysize,ResultName);
clock_t tStart = clock();
GuptaSproull g(ResultName,TestDataFile);
printf("Time taken for GuptaSproull: %.4fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);
}
However, an error is produced as follows
C++ files/ComparatorMain.o:ComparatorMain.cpp:(.text+0x544): undefined reference to `Bresenham::Bresenham(std::string, std::string)'
C++ files/ComparatorMain.o:ComparatorMain.cpp:(.text+0x76b): undefined reference to `XiaolinWu::XiaolinWu(std::string, std::string)'
C++ files/ComparatorMain.o:ComparatorMain.cpp:(.text+0x992): undefined reference to `GuptaSproull::GuptaSproull(std::string, std::string)'collect2.exe: error: ld returned 1 exit status
As the implementation of the 3 different cpp files are nearly identical (with the main difference just being the algorithm implemented as well as some misc. functions which have complied and so far aren't showing errors), I will just show the main parts of Bresenham.cpp and hpp where the linker errors are occurring (if additional information is needed, just tell me). The definitions for GuptaSproull.cpp as well as XiaolinWu.cpp are pretty much identical for the code shown below. I cut out most of the function implementations for easier reading and i don't think its relavant (unless i got that part wrong).
Bresenham.hpp
#ifndef BRESENHAM_H
#define BRESENHAM_H
#include <iostream>
#include "SDL.h"
#undef main
class Bresenham{
public:
Bresenham(std::string BMPName,std::string TestDataFile);
SDL_Surface* OpenBMP(std::string BMPName);
void CloseBMP(SDL_Surface* surface,std::string Filename);
void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel);
void bresenhamDrawLine(int x1,int y1,int x2, int y2, SDL_Surface *surface);
};
#endif
Bresenham.cpp
#ifndef BRESENHAM_H
#define BRESENHAM_H
#include <iostream>
#include <cstdio>
#include <cmath>
#include <fstream>
#include "SDL.h"
#include "Bresenham.hpp"
#undef main
#endif
class Bresenham
{
Bresenham(std::string BMPName,std::string TestDataFile)
{
std::ifstream testFile(TestDataFile);
SDL_Surface *image;
image=OpenBMP(BMPName);
if ( SDL_MUSTLOCK(image) ) //surface must be locked before pixels can be drawn
{
if ( SDL_LockSurface(image) < 0 ) {
fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
return;
}
}
int x1,y1,x2,y2;
while(testFile>>x1>>y1>>x2>>y2)
{
bresenhamDrawLine(x1,y1,x2,y2,image); //loops through the dataset and calls the bresenham draw line function
}
if ( SDL_MUSTLOCK(image) )
{
SDL_UnlockSurface(image);
}
CloseBMP(image,BMPName);
}
void bresenhamDrawLine(int x1,int y1,int x2, int y2, SDL_Surface *surface)
{
/* implemented */
}
SDL_Surface* OpenBMP(std::string BMPName)
{
/* implemented */
}
void CloseBMP(SDL_Surface *surface,std::string FileName)
{
/* implemented */
}
void putpixel(SDL_Surface *surface, int x, int y, double brightness) //this function allows us to place a pixel at coordinates (x,y) in SDL.
{
/*implemented*/
}
};
Now I have done a few messy attempts to try and fix this problem (such as adding #ifndef BRESENHAM_H #define BRESENHAM_H #include "Bresenham.hpp" into the .cpp file. However, the error above still occurs.
Is this linked to the way I implemented my code to do the testing? I used a constructor to basically run my test on the algorithms (which i suspect you might find a shoddy way of implementing such a test). I have done the following (so yeah those didn't work):
Verified that all the files are in the build path (under the same project)
Tried adding namespaces to see if it fixed the problem (it didn't)
I've searched under pretty much every single link in google in order to find a potential fix (none of them seems to work).
There are no compiler errors so far (in all the files).
I suspect i might need to abandon this style of implementing the test and migrate over to using a static function instead (Could someone comment if this would work?). I'm not really used to C++ (this is my first "big" program in this language so far), so pardon me if I'm missing something glaringly obvious (which i hope i didn't).
What should I do?
You actually have two declarations of Bresenham class, one in Bresenham.hpp and one in Bresenham.cpp. Change your cpp file in following way:
Bresenham::Bresenham(std::string BMPName,std::string TestDataFile)
{
std::ifstream testFile(TestDataFile);
SDL_Surface *image;
image=OpenBMP(BMPName);
if ( SDL_MUSTLOCK(image) ) //surface must be locked before pixels can be drawn
{
if ( SDL_LockSurface(image) < 0 ) {
fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
return;
}
}
int x1,y1,x2,y2;
while(testFile>>x1>>y1>>x2>>y2)
{
bresenhamDrawLine(x1,y1,x2,y2,image); //loops through the dataset and calls the bresenham draw line function
}
if ( SDL_MUSTLOCK(image) )
{
SDL_UnlockSurface(image);
}
CloseBMP(image,BMPName);
}
void Bresenham::bresenhamDrawLine(int x1,int y1,int x2, int y2, SDL_Surface *surface)
{
/* implemented */
}
SDL_Surface* Bresenham::OpenBMP(std::string BMPName)
{
/* implemented */
}
void Bresenham::CloseBMP(SDL_Surface *surface,std::string FileName)
{
/* implemented */
}
void Bresenham::putpixel(SDL_Surface *surface, int x, int y, double brightness) //this function allows us to place a pixel at coordinates (x,y) in SDL.
{
/*implemented*/
}
What should I do?
First of all, you need to set up correct code units:
remove #undef main (makes no sense)
remove the include guards from your cpp files, they belong only in header files. With these, the code just doesn't get compiled, hence the linking problem !
As CodeFuller states it clearly in his answer, you must separate the class declaration (in .hpp file) and the implementation of the methods (in the .cpp file)
For more, you need to gives us an MVCE that demonstrates your problem (I agree, that is some bit of work).
Related
#include "IRSensor.h"
#include "Turret.h"
#include "StepperButtonController.h"
#include "LoadBottleButton.h"
LoadBottleButton go(A3,1000);
void setup()
{
Serial.begin(9600);
Serial.println("Port Open");
}
void loop()
{
if(go.Read())
{
go.Monitor();
}
}
Above is the Main code
#ifndef LoadBottleButton_cpp
#define LoadBottleButton_cpp
#include "Arduino.h"
#include "ScaleObject.h"
#include "LoadBottleButton.h"
#include "Turret.h"
#include "StepperButtonController.h"
ScaleObject* so;
Turret* tPointer;
LoadBottleButton::LoadBottleButton(int pin, int debounce):StepperButtonController(pin,debounce)
{
}
void LoadBottleButton::Monitor()
{
Serial.println("In Monitor");
while(tPointer->getTurret().BottleCenterState==false)
{
Serial.println("In Monitor While Loop");
tPointer->Start();
SETUP = true;
load = true;
unload = !so->getScale().Empty();
Serial.println(load);
Serial.println(unload);
Serial.println(!so->getScale().Empty());
if(unload)
{
unload=!so->getScale().Empty();
}
else if(load && !so->getScale().Empty())
{
load = !tPointer->BottleCentered();
}
if(!load && !unload && SETUP)
{
tPointer->Stop();
SETUP = false;
}
}
}
#endif
And above is the LoadBottleButtonClass.cpp file.
#ifndef Turret_cpp
#define Turret_cpp
//#include "HX711.h"
#include "Turret.h"
#include "Arduino.h"
#include "StepperButtonController.h"
#include "ScaleObject.h"
#include "IRSensor.h"
//StepperButtonController Clear(9,1000);
void StepTurret();
Turret turret(2,3,4,StepTurret);
void StepTurret()
{
turret.Step();
}
ScaleObject* tso;
IRSensor* irs;
Turret::Turret()
{
}
Turret Turret::getTurret()
{
return turret;
}
Turret::Turret(int en, int dir, int clk, void(*stepFunction)()):stepper2(en,dir,clk,stepFunction)
{
tso->getScale().tare();
tso->getScale().set_gain(128);
tso->getScale().set_scale(-3483.4);
}
void Turret::SeekBottleCenter()
{
Start();
while(irs->IRState()==1)
{
Serial.println("High");
Serial.println(irs->IRState());
}
while(irs->IRState()==0)
{
Serial.println("Low");
}
}
bool Turret::BottleCentered()
{
return turret.BottleCenterState;
}
void Turret::ClearFunction()
{
wt = tso->getScale().get_units();
while(wt>5)
{
Serial.println("Clearing");
wt = tso->getScale().get_units();
Rotate(20);
}
}
#endif
And above is the Turret.cpp file.
#ifndef IRSensor_cpp
#define IRSensor_cpp
#include "Arduino.h"
#include "IRSensor.h"
IRSensor i(5);
IRSensor::IRSensor(int pin)
{
IRSensorPin = pin;
pinMode(pin,INPUT);
}
int IRSensor::IRState()
{
return digitalRead(i.IRSensorPin);
}
#endif
And above is the IRSensor.cpp file. So essentially I press the go button declared in my main, that button calls monitor in the LoadBottleButton.cpp file, that method uses a turret point to get access to the Turret.cpp methods and a boolean named BottleCenterState. But the code only gets so far, it stops after printing "In" of the Serial.println("In Monitor") line. Why is that?
Don't count on the output to tell you where the error is. That serial print may have completed successfully and the message is buffered in an output stream waiting for a chance to be written to the serial port.
A much more likely cause of the crash is the line below the serial print.
Serial.println("In Monitor");
while(tPointer->getTurret().BottleCenterState==false)
tPointer is used and I don't see anywhere in the provided code it is assigned a valid, dereferencable pointer. Dereferencing an undefined pointer results in undefined behaviour, and in this case probably a crash. Even if it isn't the crash you are seeing, this is almost certainly wrong.
How to fix it?
From the code provided it doesn't look like tpointer needs to be a pointer at all.
Turret turret;
May be all you need. Allocating turret statically eliminates the possibility of pointer and memory management bugs and reduces the chance of leaks.
Otherwise,
Turret* tPointer = new Turret();
But this leaves you with the problem of how and when do you delete tPointer;.
Check that your string doesn't contain a NULL character. This will terminate the string abruptly.
I get a lot of undefined references. I don't know what I'm doing wrong.
I'm getting the following errors:
undefined reference to 'LetteroidField::start()'
undefined reference to 'LetteroidField::setTitle(std::string)'
undefined reference to 'Letteroid::setletter(char)'
undefined reference to 'Letteroid::setLetter()'
undefined reference to 'Letteroid::setCoords()'
undefined reference to 'Letteroid::erase()'
and other letteroid references.
I'm not done with the other classes, but I don't know why I'm getting these errors. Am I not using #include "" correctly?
This is my professor's sample code. I contacted him but he is not answering (its an online class).
#include "letteroidfield.h"
#include "letteroid.h"
#include "blinkingletteroid.h"
#include "jumpingletteroid.h"
#include "movingletteroid.h"
#include <stdlib.h> /* srand, rand */
#include <time.h>
/// include your derived classes here
int main()
{
LetteroidField screen;
screen.start();
screen.setTitle("Ken's example for the class, press 'x' to quit");
BlinkingLetteroid one;
BlinkingLetteroid two;
BlinkingLetteroid three;
one.setLetter('!'); /// character
one.setCoords(5, 10); /// row, col
two.setLetter('h');
two.setCoords(7, 9);
three.setLetter('#');
three.setCoords(15, 57);
JumpingLetteroid four;
four.setLetter('j');
four.setCoords(rand() % 21, rand() % 21);
MovingLetteroid five;
five.setLetter('m');
int x = 20;
int y = 20;
while (x >= 1)
{
--x;
}
while (y >= 1)
{
--y;
}
if (x == 1)
{
x = 20;
}
if (y == 1)
{
x = 20;
}
five.setCoords(x,y);
/// create and initialize your letteroids here
while ( screen.waitForKeyPress() ) /// keep going until 'x' is pressed
{
one.blink();
two.blink();
three.blink();
/// call the function that draws your letteroids here
}
screen.end();
return 0;
}
#ifndef _LETTEROIDFIELD_H_
#define _LETTEROIDFIELD_H_
#include <string>
class LetteroidField
{
public:
void start(); /// start up the screen for letteroids
bool waitForKeyPress(); /// wait for any key to be pressed (return
void end(); /// shut down the screen and return it to
void setTitle(std::string); /// diplay the title
};
#endif
#ifndef _LETTEROID_H_
#define _LETTEROID_H_
class Letteroid
{
public:
void setCoords(int, int);// set the position(down, across)
void setLetter(char); // set the character
int getX(); // get the position down
int getY(); // get the position across
void erase(); // erase the letteroid from the screen
void draw(); // draw the letteroid to the screen
private:
int myX;
int myY;
char myLetter;
};
#endif
The question you need to ask yourself is: Where are those classes defined?
If the answer is: "in a shared library (file extension ".so") provided alongside the header", then you'll need to link against it by adding at least the following to your compilation command:
g++ main.cpp -L</path/to/library> -l<library_name>
If the answer is: "in a static library (file extension ".a", AKA archive) provided alongside the header", then you'll need include it in your binary by adding at least the following to your compilation command:
g++ main.cpp <library_name.a>
If the answer is: "in a bunch of source files provided alongside the header", then you'll need to include them in your binary by adding at least the following to your compilation command:
g++ main.cpp <source_file1.cpp> <source_file2.cpp> ...
I looked around and I couldn't find the answer to how exactly to do this. I am trying to use Pantheios for logging and I want to write to an external file (otherwise whats the point). I am following one of the examples provided but It doesn't seem to be making the log file anywhere. Here is the code:
Edit: Also pantheios_be_file_setFilePath is returning -4 (PANTHEIOS_INIT_RC_UNSPECIFIED_FAILURE) so thats.....not helpful
#include "stdafx.h"
#include <pantheios/pantheios.hpp>
#include <pantheios/implicit_link/core.h>
#include <pantheios/implicit_link/fe.simple.h>
#include <pantheios/implicit_link/be.WindowsConsole.h>
#include <pantheios/implicit_link/be.file.h>
#include <pantheios/frontends/fe.simple.h>
#include <pantheios/backends/bec.file.h>
#include <pantheios/inserters/args.hpp>
PANTHEIOS_EXTERN_C const PAN_CHAR_T PANTHEIOS_FE_PROCESS_IDENTITY[] = PANTHEIOS_LITERAL_STRING("LogTest");
int _tmain(int argc, _TCHAR* argv[])
{
try
{
pantheios_be_file_setFilePath(PANTHEIOS_LITERAL_STRING("testlogforme.log"), PANTHEIOS_BE_FILE_F_TRUNCATE, PANTHEIOS_BE_FILE_F_TRUNCATE, PANTHEIOS_BEID_ALL);
pantheios::log(pantheios::debug, "Entering main(", pantheios::args(argc,argv, pantheios::args::arg0FileOnly), ")");
pantheios::log_DEBUG("debug yo");
pantheios::log_INFORMATIONAL("informational fyi");
pantheios::log_NOTICE("notice me!");
pantheios::log_WARNING("warning!!");
pantheios::log_ERROR("error omg");
pantheios::log_CRITICAL("critical!!!");
pantheios::log_ALERT("alert mang");
pantheios::log_EMERGENCY("EMERGENCY!!!!!");
pantheios_be_file_setFilePath(NULL, PANTHEIOS_BEID_ALL);
system("pause");
return EXIT_SUCCESS;
}
catch(std::bad_alloc&)
{
pantheios::log_ALERT("out of memory");
}
catch(std::exception& x)
{
pantheios::log_CRITICAL("Exception: ", x);
}
catch(...)
{
pantheios::puts(pantheios::emergency, "Unexpected unknown error");
}
return EXIT_FAILURE;
}
Maybe I'm not calling a method or maybe its not being saved to a good location?
It turns out that some of the examples out there for pantheios are incorrect. You DO need to call pantheios_init() even if you are in C++. Here Is the example I got to work after deleting all my code and implementing an example that works.
// Headers for main()
#include <pantheios/pantheios.hpp>
#include <pantheios/backends/bec.file.h>
// Headers for implicit linking
#include <pantheios/implicit_link/core.h>
#include <pantheios/implicit_link/fe.simple.h>
#include <pantheios/implicit_link/be.file.h>
PANTHEIOS_EXTERN_C const char PANTHEIOS_FE_PROCESS_IDENTITY[] = "testLOL";
int main()
{
if(pantheios::pantheios_init() < 0)
{
return 1;
}
pantheios::log_NOTICE("log-1"); // save until log file set
pantheios_be_file_setFilePath("mylogfile.log"); // sets log file; write "log-1" stmt
pantheios::log_NOTICE("log-2"); // write "log-2" stmt
pantheios_be_file_setFilePath(NULL); // close "mylogfile"
pantheios::log_NOTICE("log-3"); // save until log file set
pantheios_be_file_setFilePath("mylogfile2.log"); // sets log file; write "log-3" stmt
pantheios::log_NOTICE("log-4"); // write "log-4" stmt
//system("pause");
return 0;
} // closes "mylogfile2" during program closedown
I found the example on a different post on stack overflow but like I said, the built in examples do not work.
Original question:
I've been asked prior to a job interview to understand how an
anti-aliased line is drawn in a framebuffer, using C or C++. I haven't
used C, and it's been a few years for me since last using C++. I am a
complete beginner when it comes to graphics. My C++ experience has
mostly been in simple command-line programs and sorting methods. The
company does not care if I grab the code online, they want me to
understand it but still have a working executable.
I've used this tutorial to set up SDL libraries in MS VC++ 2012
Express, and this algorithm for the actual anti-aliasing. I have
a good understanding of the algorithm, though I'm currently having
trouble getting it to compile. I just want a line to be drawn, and
then I can go forward with setting the code up to the skeleton class
definitions I was given. This is what I have included aside from what
is on that page with the algorithm:
#include <cmath>
#include <math.h>
#include "conio.h"
#include "stdlib.h"
#include "stdio.h"
#include "SDL.h"
const double HEIGHT = 240;
const double WIDTH = 320;
const double X0 = 25.6;
const double X1 = 64.7;
const double Y0 = 30;
const double Y1 = 42;
int round(double number)
{
return number < 0.0 ? ceil(number - 0.5) : floor(number + 0.5);
}
void main()
{
Uint32 pixelColor = 00000000000000000000000000000000;
SDL_Surface* myScreen = SDL_CreateRGBSurface(SDL_ALPHA_OPAQUE,WIDTH,HEIGHT,32, 0x000000FF,
0x0000FF00, 0x00FF0000, 0xFF000000);
WULinesAlpha(X0, X1, Y0, Y1,pixelColor,myScreen);
return;
}
I'm getting the following errors:
Error 21 error LNK2019: unresolved external symbol _SDL_main
referenced in function _main Error 22 error LNK1120: 1 unresolved
externals
I've seen a few code examples saying the main function has to look
like this:
int main(int argc, char *argv[])
{
}
Again, graphics stuff is unfamiliar to me so I know my main function
is likely very wrong; I'm anticipating some shaking heads. Can someone
explain what is happening/what I need to do?
New:
I have now replaced my main function with the following code, based on NomNomNom069's YouTube video: "C++ SDL Tutorial 2 Creating a Screen and Handling Basic Input"
#include "SDL.h"
int main(int argc, char * args[])
{
bool running = true;
//initialize SDL
if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
{
running = false;
}
//set up screen
SDL_Surface *screen;
screen = SDL_SetVideoMode(WIDTH, HEIGHT, 32, SDL_HWSURFACE);
if (screen == NULL)
{
running = false;
}
SDL_Event occur;
//main application loop
while (running)
{
SDL_PollEvent(&occur);
if (occur.type == SDL_QUIT)
{
running = false;
}
//drawing occurs here
SDL_FillRect(screen, NULL, 0);
SDL_Flip(screen);
}
//quit SDL
SDL_Quit();
return 0;
}
No errors, and I get a window to pop up. Awesome.
My question now is regarding how/where to call WuLinesAlpha. This function calls for 4 doubles, a Uint32 variable, and an SDL_Surface*. I have my doubles, I set the Uint32 to 0x000000FF, and I assume that the SDL_Surface I have set up as screen is the one passed in.
I've toyed around with where the WuLinesAlpha function call goes and I keep getting the black screen. I thought, as explained in the video, it would go in the loop but nothing has happened. Are there any more SDL commands I should be calling?
Fix your main declaration first. This does need to be int main(int argc, char *argv[]). Especially on Windows, since I believe SDL.h actually renames your main to some other name, and takes over main for the library itself.
Next, make sure you link against SDL properly. In my own SDL 1.2.x based project I have these lines in my Makefile:
SDL_CFLAGS := $(shell sdl-config --cflags)
SDL_LFLAGS := $(shell sdl-config --libs)
I then later append those flags to my actual CFLAGS and LFLAGS. Note that if you use make and Makefiles, you want to use := there, otherwise make will invoke the $(shell ...) command every time it expands $(CFLAGS).
I can't help you set up Microsoft's GUI products. This tutorial, for a slightly older MSVC product (2010), looks pretty good, and may put you on the right track: http://lazyfoo.net/SDL_tutorials/lesson01/windows/msvsnet2010e/index.php
And finally, don't forget to call SDL_Init() at some point, preferably before you start creating surfaces.
Good luck!
This question already has answers here:
static variable link error [duplicate]
(2 answers)
Closed 8 years ago.
I have no idea why this code isn't working. All the source files compile but when I try to link them the compiler yells at me with an undefined reference error. Here's the code:
main.cpp:
#include "SDL/SDL.h"
#include "Initilize.cpp"
int main(int argc, char* args[])
{
//Keeps the program looping
bool quit = false;
SDL_Event exit;
//Initilizes, checks for errors
if(Initilize::Start() == -1)
{
SDL_Quit();
}
//main program loop
while(quit == false)
{
//checks for events
while(SDL_PollEvent(&exit))
{
//checks for type of event;
switch(exit.type)
{
case SDL_QUIT:
quit = true;
break;
}
}
}
return 0;
}
Initilize.h:
#ifndef INITILIZE_H
#define INITILIZE_H
#include "SDL/SDL.h"
/* Declares surface screen, its attributes, and Start(); */
class Initilize {
protected:
static SDL_Surface* screen;
private:
static int SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP;
public:
static int Start();
};
#endif
Initilize.cpp:
#include "Initilize.h"
#include "SDL/SDL.h"
/* Initilizes SDL subsystems, sets the screen, and checks for errors */
int Initilize::Start()
{
//screen attributes
SCREEN_WIDTH = 640;
SCREEN_HEIGHT = 480;
//Bits per pixel
SCREEN_BPP = 32;
//Inits all subsystems, if there's an error, return 1
if(SDL_Init(SDL_INIT_EVERYTHING) == -1) {
return 1;
}
//sets screen
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE);
//Returns 1 if there was in error with setting the screen
if(screen == NULL) {
return 1;
}
SDL_WM_SetCaption("Game", NULL);
return 0;
}
Sorry if the code was formatted weirdly, inserting four spaces to put in a code block messed things up a little bit.
Add the following to your cpp file:
SDL_Surface* Initilize::screen = 0; // or nullptr
int Initilize::SCREEN_WIDTH = 640;
int Initilize::SCREEN_HEIGHT = 480;
int Initilize::SCREEN_BPP = 32;
Also, if these value never change, it would be good to make them const. The reason you need to add the above to your cpp file is because static member variables need to be defined outside of the class. static SDL_Surface* screen;, etc. inside your class is only a declaration, and not a definition. static members are considered special and is very similar to a global variable.
The reason for this is because static members are shared between all instances of your class. This means they can only be defined once and allowing the definition inside the class would cause multiple definitions to occur, so the C++ standard forces you to define it outside of your class (and also implies you should put the definition in a cpp file).
in Initialize.cpp do
#include "Initialize.h"
#include "SDL/SDL.h"
// this is the new line to insert
SDL_Surface* Initialize::screen = 0;
int Initialize::SCREEN_WIDTH=...; // whatever you want to set it to
int Initialize::SCREEN_HEIGHT=...; // whatever you want to set it to
int Initialize::SCREEN_BPP=...; // whatever you want to set it to
and remove the #include "Initialize.cpp" line in main.cpp
instead do
#include "Initialize.hpp"
if you're using gcc, compile using
g++ -o <output-file> main.cpp Initialize.cpp <include flags like -I> <lib flags like -L>
It appears that you never initialized your vairables. You are assigning them in the Initialize start method but didn't initialize them. Try adding in a int SCREENWIDTH; before you assign it in the source not just header file