SDL2遍历像素数组触发0xC0000005错误,请求排查解决
问题:SDL遍历图像像素时触发0xC0000005内存访问错误
Process returned -1073741819 (0xC0000005)
尝试遍历图像像素修改颜色分量时反复出现上述错误,注释掉像素遍历循环后代码可正常运行,说明问题出在循环的像素访问逻辑中。
相关函数代码:
{ SDL_Surface *retour = NULL; SDL_Color color = {255, 255, 255, 255}; int i, j, w = (int) s->w, h = (int) s->h; Uint32 *src = NULL; if(SDL_LockSurface(s) < 0) { fprintf(stderr, "Erreur SDL_LockSurface : %s", SDL_GetError()); goto lock_surface_fail; } src = (Uint32 *)s->pixels; for(i = 0; i < h; i++) { for(j = 0; j < w; j++) { SDL_GetRGB(src[i * w + j], s->format, &color.r, &color.g, &color.b); Uint8 gray = (color.r + color.g + color.b) / 3; src[i * w + j] = SDL_MapRGB(s->format, gray, gray, gray); } } printf("%d sur %d", w, h); retour = SDL_CreateRGBSurfaceWithFormatFrom(src, s->w, s->h, 32, s->pitch, s->format->format); if(NULL == retour) { fprintf(stderr, "Erreur SDL_CreateRGBSurface : %s", SDL_GetError()); } alloc_memory_fail: SDL_UnlockSurface(s); lock_surface_fail: return retour; }
出错的循环段:
for(i = 0; i < h; i++) { for(j = 0; j < w; j++) { SDL_GetRGB(src[i * w + j], s->format, &color.r, &color.g, &color.b); Uint8 gray = (color.r + color.g + color.b) / 3; src[i * w + j] = SDL_MapRGB(s->format, gray, gray, gray); } }
问题原因与修复方案
1. 核心问题:行偏移计算错误
SDL中SDL_Surface的pitch字段代表一行像素的总字节数,而非像素数量。由于内存对齐要求,pitch往往不等于w * 单个像素字节数。你直接用i * w计算行偏移,会导致内存越界访问,触发0xC0000005错误。
正确的行起始地址计算必须使用pitch:
Uint32 *row = (Uint32 *)((Uint8 *)src + i * s->pitch);
2. 次要问题:直接操作硬件表面风险
如果原Surface是硬件加速表面(比如从纹理导出的Surface),直接写入其pixels内存会触发访问违规。建议先创建一个可修改的软件Surface副本再操作。
修复后的完整代码
{ SDL_Surface *retour = NULL; SDL_Color color = {255, 255, 255, 255}; int i, j, w = (int)s->w, h = (int)s->h; Uint32 *src = NULL; // 创建可修改的软件Surface副本,避免操作硬件表面 retour = SDL_CreateRGBSurfaceWithFormat(0, w, h, 32, s->format->format); if (!retour) { fprintf(stderr, "Erreur SDL_CreateRGBSurface : %s", SDL_GetError()); goto lock_surface_fail; } SDL_BlitSurface(s, NULL, retour, NULL); if (SDL_LockSurface(retour) < 0) { fprintf(stderr, "Erreur SDL_LockSurface : %s", SDL_GetError()); goto cleanup; } src = (Uint32 *)retour->pixels; for (i = 0; i < h; i++) { // 用pitch计算每行起始地址,避免越界 Uint32 *row = (Uint32 *)((Uint8 *)src + i * retour->pitch); for (j = 0; j < w; j++) { SDL_GetRGB(row[j], retour->format, &color.r, &color.g, &color.b); // 加权计算灰度更符合人眼感知 Uint8 gray = (Uint8)(0.299 * color.r + 0.587 * color.g + 0.114 * color.b); row[j] = SDL_MapRGB(retour->format, gray, gray, gray); } } SDL_UnlockSurface(retour); printf("%d sur %d", w, h); goto end; cleanup: SDL_FreeSurface(retour); retour = NULL; lock_surface_fail: end: return retour; }
额外优化提示
- 灰度计算使用加权公式(0.299红 + 0.587绿 + 0.114蓝),比简单平均更符合人眼对色彩的感知。
- 若原Surface像素格式不是32位,直接强制转换为
Uint32*会导致错误,统一转换为32位软件Surface后处理更稳妥。
内容的提问来源于stack exchange,提问作者user23309594
相关产品推荐
相关产品推荐

