Windows VS环境libcurl下载PNG返回CURLcode 23错误求助
问题原因
CURLcode 23 对应CURLE_WRITE_ERROR,触发条件非常明确:libcurl调用写入回调时,回调返回的实际写入字节数和传入的待写入字节数不匹配,就会直接中断请求返回这个错误。
你的代码在WSL环境正常、VS下Windows环境报错,基本逃不开两个原因:
- 最核心的高频诱因:CRT运行库不匹配。Windows平台下
FILE*指针对应的内部文件结构是和所属模块的C运行时(CRT)强绑定的,如果你自己VS工程配置的运行库选项(比如静态链接的/MT、/MTd)和你链接的libcurl库编译时用的运行库选项(比如动态链接的/MD、/MDd)不一致,libcurl内部调用默认的fwrite往你传的fp里写数据时,会因为跨CRT无法识别FILE结构直接写入失败,返回的写入字节数不符合预期,直接抛23错误。Linux环境下不存在这个CRT隔离的问题,所以同一份代码可以正常跑。 - 代码逻辑漏判:你现在的逻辑在
fopen返回NULL(文件打开失败,比如权限不足、路径非法)时,只打印了一行提示,没有做分支拦截,后续还是会把空指针传给CURLOPT_WRITEDATA,libcurl往空指针写数据必然失败,也会返回23。
修复方案
- 先对齐CRT运行库配置
打开VS项目属性页,找到「C/C++ -> 代码生成 -> 运行库」选项,和你使用的libcurl版本的编译配置保持完全一致:- 如果用的是官方预编译的libcurl动态库(dll形式),Debug模式选
多线程调试DLL (/MDd),Release模式选多线程DLL (/MD) - 如果是自己编译的静态libcurl,就选和你编译libcurl时完全相同的运行库选项
- 如果用的是官方预编译的libcurl动态库(dll形式),Debug模式选
- 补全文件打开失败的拦截逻辑,打开失败直接走清理逻辑,不要继续执行curl请求
- 最稳妥的兜底方案:自己实现写入回调,彻底规避跨CRT的FILE*识别问题——回调函数在你自己的程序代码里执行,用的是当前工程的CRT,完全不会有跨模块识别问题。
修复后的可运行代码如下:
#include <stdio.h> #include <curl/curl.h> // 自定义写回调,逻辑和默认fwrite完全一致,但是在本工程内执行 static size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp) { size_t written = fwrite(contents, size, nmemb, (FILE*)userp); return written; } int main() { char url[100] = "http://url_to.png"; // 替换为实际PNG地址 CURL *curl = curl_easy_init(); CURLcode res; FILE *fp = NULL; if (curl) { fp = fopen("./sample.png", "wb"); if (fp == NULL) { printf("File cannot be opened\n"); curl_easy_cleanup(curl); return 1; } curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); // 建议加超时配置,避免异常场景下请求挂死 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L); res = curl_easy_perform(curl); if (res != CURLE_OK) { printf("Cannot grab the image! Error Code: %d, error msg: %s\n", res, curl_easy_strerror(res)); } fclose(fp); curl_easy_cleanup(curl); } return 0; }
补充说明:如果对齐CRT之后还是报错,检查下当前程序运行的工作目录是否有写入权限,部分情况下VS启动程序时的工作目录是项目根目录不是生成的exe所在目录,路径权限异常也可能导致写入失败。
内容的提问来源于stack exchange,提问作者Ignorant Potato
相关产品推荐
相关产品推荐

