4

The code posted is copied directly from an example of a popular SDL2 tutorial, to ensure that it wasn't I who had made some silly mistake. All I've done to the example is changing the path of the image file in question, I changed type bool to int, false to 0 and true to 1. As I understand it, nothing C++ specific should remain.

Everything seems to work regardless what I do, but when compiling with CC/GCC (I suppose that's really the same deal) I get a segmentation fault in the very end, I suspect in close(), which I've been unable to determine. Compiling with G++ somehow prevents the segmentation fault.

The solution of course is simple, just use G++, but I would very much like to know wherein the problem lies.

main.c:

//Using SDL and standard IO
#include <SDL2/SDL.h>
#include <stdio.h>

//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

//Starts up SDL and creates window
int init();

//Loads media
int loadMedia();

//Frees media and shuts down SDL
void close();

//The window we'll be rendering to
SDL_Window* gWindow = NULL;

//The surface contained by the window
SDL_Surface* gScreenSurface = NULL;

//The image we will load and show on the screen
SDL_Surface* gHelloWorld = NULL;

int init()
{
    //Initialization flag
    int success = 1;

    //Initialize SDL
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    {
        printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
        success = 0;
    }
    else
    {
        //Create window
        gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED,
                                    SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH,
                                    SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
        if( gWindow == NULL )
        {
            printf( "Window could not be created! SDL_Error: %s\n",
                    SDL_GetError() );
            success = 0;
        }
        else
        {
            //Get window surface
            gScreenSurface = SDL_GetWindowSurface( gWindow );
        }
    }

    return success;
}

int loadMedia()
{
    //Loading success flag
    int success = 1;

    //Load splash image
    gHelloWorld = SDL_LoadBMP( "hello_world.bmp" );
    if( gHelloWorld == NULL )
    {
        printf( "Unable to load image %s! SDL Error: %s\n", "hello_world.bmp",
                SDL_GetError() );
        success = 0;
    }

    return success;
}

void close()
{
    //Deallocate surface
    SDL_FreeSurface( gHelloWorld );
    gHelloWorld = NULL;

    //Destroy window
    SDL_DestroyWindow( gWindow );
    gWindow = NULL;

    //Quit SDL subsystems
    SDL_Quit();
}

int main( int argc, char* args[] )
{
    //Start up SDL and create window
    if( !init() )
    {
        printf( "Failed to initialize!\n" );
    }
    else
    {
        //Load media
        if( !loadMedia() )
        {
            printf( "Failed to load media!\n" );
        }
        else
        {
            //Apply the image
            SDL_BlitSurface( gHelloWorld, NULL, gScreenSurface, NULL );

            //Update the surface
            SDL_UpdateWindowSurface( gWindow );

            //Wait two seconds
            SDL_Delay( 2000 );
        }
    }

    //Free resources and close SDL
    close();

    return 0;
}

I don't see how it's relevant, but just to be on the safe side, here's the standard Makefile I'm using

#OBJS specifies which files to compile as part of the project
OBJS = main.c

#CC specifies which compiler we're using
CC = cc

#COMPILER_FLAGS specifies the additional compilation options we're using
# -w suppresses all warnings
COMPILER_FLAGS = -Wall -Wextra -pedantic

#LINKER_FLAGS specifies the libraries we're linking against
LINKER_FLAGS = -lSDL2

#OBJ_NAME specifies the name of our exectuable
OBJ_NAME = test

#This is the target that compiles our executable
all : $(OBJS)
    $(CC) $(OBJS) $(COMPILER_FLAGS) $(LINKER_FLAGS) -o $(OBJ_NAME)

I get no errors or warnings but unused argv and argc.

At this point I'm at a dead end, thus I ask here.

Best regards.

NB: I should be mentioned that whatever the issue, it's most definitely not a hardware issue, various search results have suggested, as I get the exact same result and problem, on two entirely different hardware platforms.

Zacariaz
  • 537
  • 2
  • 7
  • 13
  • 4
    Completely unrelated to your question, but you're using the line-continuation `'\'` character in situations where it's not necessary. Typically it's only needed in macro definitions that run over multiple lines. – Michael Burr Jul 08 '15 at 22:09
  • Ah, I forgot about that. Usually I wouldn't have included it. It's dues to my environment. I know they're not necessary, but I like having them there. I just like being able to see clearly when something runs over multiple lines. – Zacariaz Jul 08 '15 at 22:17
  • 1
    What is `close();` supposed to do? [ and: why should I detect this, while your compiler does not?] There is a local function called close(), but please don't do this. – wildplasser Jul 08 '15 at 22:20
  • 1
    Note: There was no need to change boolean type. C _does_ have the same since C99 (just `#include `. Hint: To suppress warnings about unused arguments, I just `argc = argc; argv = argv;`. – too honest for this site Jul 08 '15 at 22:22
  • Deallocate memory and reset a couple of pointers. Seems pretty clear to me. – Zacariaz Jul 08 '15 at 22:22
  • @Olaf. I considered that, but it seems pretty needless to me. I don't suppose it would make any practical difference other than perhaps for explanatory purposes? – Zacariaz Jul 08 '15 at 22:27
  • I assume you refer the hint: Just take it as such. I enable most warnings for my code. Now, as I do not tolerate warnings (turning into errors for release builds), such warnings have to be silenced intentionally. Of course, there will be a clear comment. – too honest for this site Jul 08 '15 at 22:33
  • I was actually referring to the use of stdbool.h. I know it's my OCD playing tricks on be, but having to remember to include a bunch of headers for minor convenience and potentially major confusion, is not something I like to do. I think these types should be native if used. I occasionally use stdint.h, but that's for other reasons. As for the hint to suppress warning, I've already done as you suggested. – Zacariaz Jul 08 '15 at 22:44
  • 1
    Does the behavior change if you rename `close()` to a name that's not part of the C standard library? – aschepler Jul 08 '15 at 23:06
  • Yes, I just figured it out on my own just a couple of minutes ago, trying to determine where the segmentation fault occurred, which gave very odd results, where the same line of code were execute multiple time, almost like some sort of recursion occurred, and after that the conclusions seemed simple enough. Wonder why I didn't figure that out earlier. – Zacariaz Jul 08 '15 at 23:24
  • 1
    I faced this same problem, and I've spent whole day until I finally find this question! `close()` function the same I did on my end. Surprisingly I always keep best practice of using `static ....` in front of function definition, but this time I let loose which is debt for me at the end. Ok, remind myself, always `static` prefixed for functions that supposed to be used locally in that file only. Thanks for asking this! – haxpor Mar 27 '19 at 18:06

1 Answers1

6

If you rename the function close() the segfault goes away, looks like init() calls into SDL which calls into X11 which calls into your driver which calls close(), but instead of calling the right close() it calls yours instead. In C++ functions will get name mangled to something else so it it not a problem.

yngccc
  • 5,594
  • 2
  • 23
  • 33
  • That's what I said in the comments. – wildplasser Jul 08 '15 at 23:11
  • 1
    Yes, you did indeed, but I didn't see it in time to actually be of any help. I actually figured it out on my own. In any case the result was the same. It seems quite odd to me, but I got the solution I asked for. Thank you. – Zacariaz Jul 08 '15 at 23:26