Win10x64平台调用png_read_png后printf无输出问题求助
调用libpng的png_read_png后程序停止执行,printf无输出
环境信息
- 平台:Win10 x64
- 编译器:GCC
- 语言:C
- 依赖库:libpng16.dll
问题描述
调用png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);之后,后续的printf完全没有输出,程序卡在这一步或直接终止。已经尝试在printf末尾加换行,也手动调用了fflush(stdout),但都无效。
原始代码
#include <stdio.h> #include <png.h> int main(int argc, char* argv[]) { printf("starting...\n"); FILE *fp = fopen("test.png", "rb"); if (!fp) { printf("error #%d\n", 1); } // Read the PNG header png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { printf("error #%d\n", 2); } // create stuct for png info/meta data png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { printf("error #%d\n", 3); } if (setjmp(png_jmpbuf(png_ptr))) { printf("error #%d\n", 4); } png_init_io(png_ptr, fp); // Read the PNG image data printf("before printf dies\n"); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); printf("this will not print after png_read_png is ran\n"); fflush(stdout); /* it won't print regardless if the below cleanup code is commented out or not */ // Get the image dimensions and bit depth png_uint_32 width, height; int bit_depth, color_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); // Allocate memory for the image data png_bytep *row_pointers = png_malloc(png_ptr, height * sizeof(png_bytep)); for (png_uint_32 i = 0; i < height; i++) { row_pointers[i] = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); } // Read the image data into memory png_read_image(png_ptr, row_pointers); // Clean up png_destroy_read_struct(&png_ptr, &info_ptr, NULL); // Free the memory allocated for the image data for (png_uint_32 i = 0; i < height; i++) { png_free(png_ptr, row_pointers[i]); } png_free(png_ptr, row_pointers); /**/ fclose(fp); return 0; }
程序输出
starting... before printf dies
问题原因与修复方案
核心问题
- libpng的错误跳转机制:libpng用
setjmp/longjmp处理错误,当png_read_png执行出错时,会直接跳转到之前setjmp的位置,不会执行后续代码。你的错误分支只打印了错误,没有终止程序或清理资源,导致程序继续执行异常代码。 - 重复读取操作:
png_read_png已经完成了图像数据的读取,后续又调用png_read_image属于重复读取,会触发错误。 - 资源错误未及时终止:文件打开、结构创建失败时,只是打印错误却继续执行,导致后续操作使用无效指针,触发跳转。
修复步骤
- 完善错误跳转后的处理:在
setjmp分支里清理资源并退出程序:
if (setjmp(png_jmpbuf(png_ptr))) { printf("error #%d: 读取PNG文件出错\n", 4); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return 1; }
- 移除重复读取代码:删掉
png_read_image及手动分配行指针的代码,直接用png_get_rows(png_ptr, info_ptr)获取已读取的行数据。 - 及时终止错误流程:文件、结构创建失败时,清理已分配资源后立即退出,避免后续无效操作:
FILE *fp = fopen("test.png", "rb"); if (!fp) { printf("error #%d: 无法打开文件\n", 1); return 1; }
修复后代码示例
#include <stdio.h> #include <png.h> int main(int argc, char* argv[]) { printf("starting...\n"); FILE *fp = fopen("test.png", "rb"); if (!fp) { printf("error #%d: 无法打开文件\n", 1); return 1; } png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) { printf("error #%d: 创建PNG读取结构失败\n", 2); fclose(fp); return 1; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { printf("error #%d: 创建PNG信息结构失败\n", 3); png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(fp); return 1; } if (setjmp(png_jmpbuf(png_ptr))) { printf("error #%d: 读取PNG文件出错\n", 4); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return 1; } png_init_io(png_ptr, fp); printf("before png_read_png\n"); png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); printf("png_read_png执行完成,后续代码正常运行\n"); // 获取图像信息 png_uint_32 width, height; int bit_depth, color_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); printf("图像尺寸:%ux%u,位深:%d,颜色类型:%d\n", width, height, bit_depth, color_type); // 获取已读取的行指针 png_bytep *row_pointers = png_get_rows(png_ptr, info_ptr); // 此处可添加图像数据处理逻辑 // 清理资源 png_destroy_read_struct(&png_ptr, &info_ptr, NULL); fclose(fp); return 0; }
额外技巧
可以给libpng设置自定义错误回调,获取更详细的错误信息:
void png_error_fn(png_structp png_ptr, png_const_charp msg) { fprintf(stderr, "PNG错误详情: %s\n", msg); longjmp(png_jmpbuf(png_ptr), 1); } // 创建读取结构时传入回调 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, png_error_fn, NULL);
内容的提问来源于stack exchange,提问作者user353885
相关产品推荐
相关产品推荐

