在函数内创建渲染器时的SDL2 Segfault

时间:2015-07-26 09:07:48

标签: c sdl

使用sdl2库,我尝试在函数内创建窗口,曲面和渲染器,但我一直在接收段错误。我在这里有我的init_display函数:

void init_display (SDL_Window *window, SDL_Surface *surface, SDL_Renderer *renderer, int window_width, int window_height) {

    SDL_Init(SDL_INIT_VIDEO);

    window = SDL_CreateWindow("Cellular Automaton", 0, 0, window_width, window_height, SDL_WINDOW_SHOWN);
    surface = SDL_GetWindowSurface(window);
    renderer = SDL_CreateSoftwareRenderer(surface);

    SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
    SDL_RenderClear(renderer);
}

在执行期间,我的程序调用第二个函数,该函数使用刚创建的渲染器,特别是SDL_SetRenderDrawColor

void draw_blocks (SDL_Renderer *renderer, int grid[], int x_blocks, int y_blocks, int block_size, int border_size, int window_width, int window_height) {
    int x, y;

    SDL_Rect blocks[x_blocks][y_blocks];
    for (y = 0; y < y_blocks; ++y) {
        for (x = 0; x < x_blocks; ++x) {
            blocks[x][y].x = (x * (block_size + border_size)) + border_size;
            blocks[x][y].y = (y * (block_size + border_size)) + border_size;
            blocks[x][y].w = block_size;
            blocks[x][y].h = block_size;
        }
    }

    for (x = 0; x < (x_blocks * y_blocks); ++x) {
        if (grid[x] == 1) {
            SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);
            SDL_RenderFillRect (renderer, &blocks[x % x_blocks][x / x_blocks]);
        }
        else if (grid[x] == 0) {
                SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
                SDL_RenderFillRect (renderer, &blocks[x % x_blocks][x / x_blocks]);

        }
    }
}

我最后通过这个函数draw_blocksSDL_SetRenderDrawColor跟踪了段错误。这是我的gdb输出:

(gdb) run

Starting program: /home/arch/dev/cell/cell 

[Thread debugging using libthread_db enabled]

Using host libthread_db library "/usr/lib/libthread_db.so.1".

Xlib:  extension "GLX" missing on display ":0.0".



Breakpoint 1, draw_borders (renderer=0xffffffffffffffff, x_blocks=80, y_blocks=80, block_size=8, border_size=1, window_width=721, window_height=721) at ./cell.c:112

112     SDL_SetRenderDrawColor(renderer, 0x7F, 0x7F, 0x7F, 0xFF);

(gdb) step

SDL_SetRenderDrawColor (a=0xffffffffffffffff, b=127 '\177', c=127 '\177', d=127 '\177', e=255 '\377') at /home/arch/downloads/sdl/src/dynapi/SDL_dynapi_procs.h:365

365 SDL_DYNAPI_PROC(int,SDL_SetRenderDrawColor,(SDL_Renderer *a, Uint8 b, Uint8 c, Uint8 d, Uint8 e),(a,b,c,d,e),return)

(gdb) next

SDL_SetRenderDrawColor_REAL (renderer=0xffffffffffffffff, r=127 '\177', g=127 '\177', b=127 '\177', a=255 '\377') at /home/arch/downloads/sdl/src/render/SDL_render.c:1281

1281    {

(gdb) step

1282        CHECK_RENDERER_MAGIC(renderer, -1);

(gdb) step



Program received signal SIGSEGV, Segmentation fault.

0x00007ffff7b0c410 in SDL_SetRenderDrawColor_REAL (renderer=0xffffffffffffffff, r=127 '\177', g=127 '\177', b=127 '\177', a=255 '\377') at /home/arch/downloads/sdl/src/render/SDL_render.c:1282

1282        CHECK_RENDERER_MAGIC(renderer, -1);

(gdb) up

#1  0x00000000004014b6 in draw_borders (renderer=0xffffffffffffffff, x_blocks=80, y_blocks=80, block_size=8, border_size=1, window_width=721, window_height=721) at ./cell.c:112

112     SDL_SetRenderDrawColor(renderer, 0x7F, 0x7F, 0x7F, 0xFF);

(gdb) up

#2  0x0000000000400d19 in main () at ./cell.c:38

38      draw_borders (renderer, x_blocks, y_blocks, block_size, border_size, window_width, window_height);

(gdb) up

Initial frame selected; you cannot go up.

(gdb)

我觉得它的指针和参考文献存在问题,但我现在没有那么多经验。根据我的阅读和思考,我认为使用renderer = SDL_CreateSoftwareRenderer(surface);创建的渲染器只是init_display函数本地的渲染器,而不是传递给main函数; SDL_SetRenderDrawColor然后尝试使用不存在的渲染器,但我可能错了。我尝试过研究和尝试各种修复,但我最终创建了一个renderer**参数(SDL_SetRenderDrawColor需要renderer*),或者我最终完全取消引用指针并使其成为renderer 。如何在main之外的函数中正确创建渲染器?这甚至是与我的段错相关的问题吗?

1 个答案:

答案 0 :(得分:3)

您的问题在于init_display功能。在C中,函数参数由value传递,因此当您执行window = SDL_CreateWindow实际更改函数本地window变量时,您最初传递给此函数的变量值保持不变。

但是,您可以传递指针指针:

void init_display (SDL_Window **window, SDL_Surface **surface, SDL_Renderer **renderer, int window_width, int window_height) {

    SDL_Init(SDL_INIT_VIDEO);

    *window = SDL_CreateWindow("Cellular Automaton", 0, 0, window_width, window_height, SDL_WINDOW_SHOWN);
    *surface = SDL_GetWindowSurface(*window);
    *renderer = SDL_CreateSoftwareRenderer(*surface);

    SDL_SetRenderDrawColor(*renderer, 0xFF, 0xFF, 0xFF, 0xFF);
    SDL_RenderClear(*renderer);
}

(不是一个好的代码,过分使用指针解除引用,但这会起作用)

然后当你调用这个函数时:

SDL_Window *window;
SDL_Surface *surface;
SDL_Renderer *renderer;
init_display(&window, &surface, &renderer);

其他代码不应要求任何更改。

您还可以将指针传递给包含所需字段的结构,并从函数中填充此结构。当你有很多领域时,它实际上很常见。

在旁注 - 如果您只需要渲染器并且对窗口或曲面没有兴趣,为什么不将渲染器设为您的函数的返回值?例如。 SDL_Renderer *init_display(int w, int h)

稍微好一点的代码版本会在本地变量中缓存指针以消除不必要的解除引用:

void init_display (SDL_Window **window, SDL_Surface **surface, SDL_Renderer **renderer, int window_width, int window_height) {

    SDL_Init(SDL_INIT_VIDEO);

    SDL_Window *_window = SDL_CreateWindow("Cellular Automaton", 0, 0, window_width, window_height, SDL_WINDOW_SHOWN);
    SDL_Surface *_surface = SDL_GetWindowSurface(_window);
    SDL_Renderer *_renderer = SDL_CreateSoftwareRenderer(_surface);

    SDL_SetRenderDrawColor(_renderer, 0xFF, 0xFF, 0xFF, 0xFF);
    SDL_RenderClear(_renderer);

    *window = _window;
    *surface = _surface;
    *renderer = _renderer;
}