使用fread读取GLSL着色器文件时多出6个字符的问题咨询
fread读取GLSL文件多出字符的问题分析与解决
原因分析
- 未检查文件打开状态:如果
fopen因路径错误、权限不足等原因失败,fshader会返回NULL,后续fseek、ftell、fread的操作都是未定义行为,得到的fsize是随机值,malloc分配的空间大小错误,最终读取到内存中的垃圾数据(比如你看到的_to_te)。 - 文本模式的换行转换:在Windows系统中,用
"r"文本模式打开文件时,系统会自动将文件中的\r\n(Windows换行)转换为\n(Unix换行),这会导致ftell获取的文件实际字节数大于fread实际读取的字符数。此时直接按fsize设置字符串终止符,会把内存中未被fread填充的垃圾区域包含进来。 - 未校验fread的实际读取量:
fread不一定能读取到fsize个字节(比如文件读取中途出错),直接用fsize设置终止符会导致未初始化的内存内容被当成有效数据。
解决方法
1. 使用二进制模式打开文件
将fopen的模式改为"rb",禁用系统的换行符转换,让ftell获取的大小与fread读取的字节数完全匹配:
fshader = fopen("src/graphics/_fragment.shader", "rb");
2. 完善错误检查逻辑
为每一步IO操作添加错误校验,避免未定义行为:
FILE *fshader = fopen("src/graphics/_fragment.shader", "r"); if (!fshader) { perror("Failed to open fragment shader"); return -1; } if (fseek(fshader, 0L, SEEK_END) != 0) { perror("Failed to seek file end"); fclose(fshader); return -1; } long fsize = ftell(fshader); if (fsize == -1) { perror("Failed to get file size"); fclose(fshader); return -1; } rewind(fshader); char *fbuffer = (char *)malloc(fsize + 1); if (!fbuffer) { perror("Failed to allocate memory"); fclose(fshader); return -1; } size_t read_bytes = fread(fbuffer, 1, fsize, fshader); // 用实际读取的字节数设置字符串终止符,避免垃圾数据 fbuffer[read_bytes] = '\0'; // 使用后记得清理资源 fclose(fshader); // ... 使用fbuffer ... free(fbuffer);
3. 更可靠的动态读取方式(推荐)
避免依赖fseek和ftell,改用getline动态读取文件内容,自动处理内存分配和换行符:
FILE *fshader = fopen("src/graphics/_fragment.shader", "r"); if (!fshader) { perror("Failed to open shader file"); return -1; } char *fbuffer = NULL; size_t buffer_capacity = 0; ssize_t read_len; // 逐行读取,getline会自动扩展缓冲区 while ((read_len = getline(&fbuffer, &buffer_capacity, fshader)) != -1) { // 可在此处理每行内容,或直接使用拼接后的fbuffer } // 使用fbuffer进行后续操作... fclose(fshader); free(fbuffer);
内容的提问来源于stack exchange,提问作者user2980746
相关产品推荐
相关产品推荐

