在SDL3中,如何通过appstate传递一个指针数组?

后端开发 2026-07-10

这是一个简单的 SDL3helloworld.cpp 程序,能够成功渲染文本“Hello, World!”

#define SDL_MAIN_USE_CALLBACKS 1 // NOLINT
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>

const int static WIDTH = 600;
const int static HEIGHT = 600;
const int static MAX = 255;
const float static SCALE = 4.0F;
const char static *MESSAGE = "Hello, World!"; // NOLINT

/* This function runs once at startup. */
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) { // NOLINT

  SDL_Window *window = nullptr;
  SDL_Renderer *renderer = nullptr;

  /* Create the window */
  if (!SDL_CreateWindowAndRenderer(MESSAGE, WIDTH, HEIGHT, SDL_WINDOW_RESIZABLE,
                                   &window, &renderer)) {
    SDL_Log("Couldn't create window and renderer: %s", // NOLINT
            SDL_GetError());                           // NOLINT
    return SDL_APP_FAILURE;
  }
  *appstate = renderer;
  return SDL_APP_CONTINUE;
}

/* This function runs once per frame, and is the heart of the program. */
SDL_AppResult SDL_AppIterate(void *appstate) { // NOLINT
  auto *local_renderer = static_cast<SDL_Renderer *>(appstate);
  int width = 0;
  int height = 0;

  /* Center the message and scale it up */
  SDL_GetRenderOutputSize(local_renderer, &width, &height);
  SDL_SetRenderScale(local_renderer, SCALE, SCALE);
  const float xpos = ((static_cast<float>(width) / SCALE) -
                      (static_cast<float>(SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE) *
                       SDL_strlen(MESSAGE))) /
                     2;
  const float ypos = ((static_cast<float>(height) / SCALE) -
                      SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE) /
                     2;

  /* Draw the message */
  SDL_SetRenderDrawColor(local_renderer, 0, 0, 0, MAX);
  SDL_RenderClear(local_renderer);
  SDL_SetRenderDrawColor(local_renderer, MAX, MAX, MAX, MAX);
  SDL_RenderDebugText(local_renderer, xpos, ypos, MESSAGE);
  SDL_RenderPresent(local_renderer);

  return SDL_APP_CONTINUE;
}

/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) { // NOLINT
  if (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_QUIT) {
    return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
  }
  return SDL_APP_CONTINUE;
}

/* This function runs once at shutdown. */
void SDL_AppQuit(void *appstate, SDL_AppResult result) {
} // NOLINT misc-use-anonymous-namespace

下面是我对参数 appstate 的理解,它是 SDL3 API 的一部分-

函数 SDL_AppInit 的第一个参数 appstate,预期是一个指向数组的指针。接近函数末尾时 -

*appstate = renderer;

指向 renderer 的指针被赋值给 appstate 数组的第一个元素。函数 SDL_AppIterate 通过第一个参数接收这个指针,然后 -

auto *local_renderer = static_cast<SDL_Renderer *>(appstate);

这个指针被强制转换为 local_renderer,它是指向同一渲染器的指针,该渲染器是在 SDL_AppInit 中创建的

接下来我尝试向 appstate 数组添加一个指向 window 的指针。我的做法是在 SDL_AppInit 中声明一个包含指向 rendererwindow 的指针的数组,并通过 appstate 传递。在函数 SDL_AppInit 中,我声明了一个指向长度为2 的数组的指针 -

void *state[2];

然后用指向 rendererwindow 的指针来填充该数组

state[0] = renderer;
state[1] = window;

现在我想把这个数组的指针赋给 appstate

appstate = (void **)&state;

问题在于,这个指针没有通过 appstate 参数在 SDL_AppIterate 中接收

下面是我修改后的Hello, World! 程序,但它不起作用 -

#define SDL_MAIN_USE_CALLBACKS 1 // NOLINT
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>

const int static WIDTH = 600;
const int static HEIGHT = 600;
const int static MAX = 255;
const float static SCALE = 4.0F;
const char static *MESSAGE = "Hello, World!"; // NOLINT

/* This function runs once at startup. */
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) { // NOLINT

  SDL_Window *window = nullptr;
  SDL_Renderer *renderer = nullptr;
  void *state[2];

  /* Create the window */
  if (!SDL_CreateWindowAndRenderer(MESSAGE, WIDTH, HEIGHT, SDL_WINDOW_RESIZABLE,
                                   &window, &renderer)) {
    SDL_Log("Couldn't create window and renderer: %s", // NOLINT
            SDL_GetError());                           // NOLINT
    return SDL_APP_FAILURE;
  }
  state[0] = renderer;
  state[1] = window;
  appstate = (void **)&state;
  return SDL_APP_CONTINUE;
}

/* This function runs once per frame, and is the heart of the program. */
SDL_AppResult SDL_AppIterate(void *appstate) { // NOLINT
// From the debugger I see appstate is empty, it should be pointer to the array passed in at the end of SDL_AppInit
  auto **state = static_cast<void **>(appstate);
  auto *local_renderer = static_cast<SDL_Renderer *>(state[0]);
  int width = 0;
  int height = 0;

  /* Center the message and scale it up */
  SDL_GetRenderOutputSize(local_renderer, &width, &height);
  SDL_SetRenderScale(local_renderer, SCALE, SCALE);
  const float xpos = ((static_cast<float>(width) / SCALE) -
                      (static_cast<float>(SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE) *
                       SDL_strlen(MESSAGE))) /
                     2;
  const float ypos = ((static_cast<float>(height) / SCALE) -
                      SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE) /
                     2;

  /* Draw the message */
  SDL_SetRenderDrawColor(local_renderer, 0, 0, 0, MAX);
  SDL_RenderClear(local_renderer);
  SDL_SetRenderDrawColor(local_renderer, MAX, MAX, MAX, MAX);
  SDL_RenderDebugText(local_renderer, xpos, ypos, MESSAGE);
  SDL_RenderPresent(local_renderer);

  return SDL_APP_CONTINUE;
}

/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) { // NOLINT
  if (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_QUIT) {
    return SDL_APP_SUCCESS; /* end the program, reporting success to the OS. */
  }
  return SDL_APP_CONTINUE;
}

/* This function runs once at shutdown. */
void SDL_AppQuit(void *appstate, SDL_AppResult result) {
} // NOLINT misc-use-anonymous-namespace

我到底哪里出错了?

解决方案

SDL_AppInit(void **appstate,... 中,你可以返回指向某些用户自定义信息的指针。当只返回一个指向 SDL_Renderer 的指针时,你不需要进行任何内存分配(因为SDL框架内部保存着 appstate 指向的指针)。

如果你需要返回两个指针,就需要为它们分配空间。示例:

struct RendererAndWindow {
    SDL_Renderer* m_renderer;
    SDL_Window* m_window;
};

SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {

    SDL_Window* window = nullptr;
    SDL_Renderer* renderer = nullptr;

    if(!SDL_CreateWindowAndRenderer(MESSAGE, WIDTH, HEIGHT,
                                    SDL_WINDOW_RESIZABLE, &window, &renderer)) {
        SDL_Log("Couldn't create window and renderer: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
    *appstate = new RendererAndWindow{renderer, window}; // allocate
    return SDL_APP_CONTINUE;
}

然后在 SDL_AppIterate

SDL_AppResult SDL_AppIterate(void* appstate) { // NOLINT
    auto raw = static_cast<RendererAndWindow*>(appstate);
    auto local_renderer = raw->m_renderer;
    //...

注意:在关闭时需要 delete 已分配的 RendererAndWindow,以避免内存泄漏。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章