如何在 C 中同时使用 GTK 和 libcurl?
How to use GTK and libcurl at the same time in C?
我正在尝试用 GTK 开发一个 C 应用程序用于 GUI,libcurl 用于通过网络获取数据 API 和 cJSON 用于解析 JSON。
我的问题是,当我在 gtk_init 之后使用 libcurl 发出请求时,我得到的数据无法在 JSON 中解析。否则,如果我在 gtk_init 之前获取数据并解析它,解析工作正常。
我有一个例子来演示它,主要 returns 中的第一个 printf 和 JSON 正确但第二个 printf 在 gtk_init returns NULL (确切地说,解析在第一个十进制数处停止并失败):
初始化字符串:
void initString(String * s) {
s->len = 0;
s->ptr = malloc(s->len + 1);
if (s->ptr == NULL) {
fprintf(stderr, "malloc() failed\n");
exit(EXIT_FAILURE);
}
s->ptr[0] = '[=10=]';
}
写函数:
size_t writeFunc(void *ptr, size_t size, size_t nmemb, String * s)
{
size_t newLen = s->len + size*nmemb;
s->ptr = realloc(s->ptr, newLen + 1);
if (s->ptr == NULL) {
fprintf(stderr, "realloc() failed\n");
exit(EXIT_FAILURE);
}
memcpy(s->ptr + s->len, ptr, size * nmemb);
s->ptr[newLen] = '[=11=]';
s->len = newLen;
return size * nmemb;
}
我使用 libcurl 获取数据的函数:
char * getData(gpointer user_data)
{
curl_global_init(CURL_GLOBAL_ALL);
CURL * curl;
char * url = user_data;
CURLcode res;
String s;
struct curl_slist * headers = NULL;
curl = curl_easy_init();
if(curl)
{
initString(&s);
headers = curl_slist_append(headers, "Accept: application/json");
headers = curl_slist_append(headers, "Content-Type: application/json");
headers = curl_slist_append(headers, "charsets: utf-8");
//curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_easy_setopt(curl, CURLOPT_SSLVERSION, 6);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
//write data in a string
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunc);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
res = curl_easy_perform(curl);
}
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
return s.ptr;
}
主要 :
int main(int argc, char ** argv)
{
char * str;
cJSON * json;
str = getData("https://data.culture.gouv.fr/api/records/1.0/search/?dataset=liste-et-localisation-des-musees-de-france&facet=ville&sort=ville&facet=nomdep&refine.nomdep=AIN&rows=1");
json = cJSON_Parse(str);
printf("DATA : %s\n", cJSON_Print(json));//returns the JSON perfectly
gtk_init(&argc,&argv);
str = getData("https://data.culture.gouv.fr/api/records/1.0/search/?dataset=liste-et-localisation-des-musees-de-france&facet=ville&sort=ville&facet=nomdep&refine.nomdep=AIN&rows=1");
json = cJSON_Parse(str);
printf("ERROR : %s\n", cJSON_GetErrorPtr());//returns half of data
printf("DATA : %s\n", cJSON_Print(json));//returns NULL
gtk_main();
curl_global_cleanup();
return EXIT_SUCCESS;
}
我试图通过使用 g_idle_add、gdk_threads_idle_add、gdk_threads_entry 和 gdk_threads_leave、pthread_create 和 pthread_join 创建线程来解决这个问题但没有任何效果。
有人知道如何解决这个问题吗?
谢谢。
我非常怀疑这与 gtk_init() 调用有任何关系。这听起来像内存损坏。这可能是这种情况,例如如果您返回指向分配的数据的指针,然后由 curl 清理。在这种情况下,两次调用都是错误的,你只是碰巧第一次逃脱了它,因为在这种情况下,内存没有被触及。检查 API 是否有您进行的函数调用。有些会分配需要释放的内存,有些则不会。
我建议您使用带有-g 的构建并使用gdb 来测试您的代码。这将有助于缩小问题所在的范围。看看字符串是否相同。
cURL returns前后相同的数据,我通过将数据放入2个字符串和strcmp returns 0.
进行检查
的确,我是法国人,,
和 .
之间可能存在混淆。
gtk_disable_setlocale
解决了我的问题!
您需要缩小问题范围。换句话说,你需要 "M" in MVCE。目前您拥有三个图书馆:
- Gtk+
- cURL
- cJSON
可能以任意方式进行交互。您需要检查的内容:
cURLreturn调用前后数据是否不同?如果不是,则问题不在于 cURL。
如果你在程序中硬编码JSON数据,然后用cJSON解析,gtk_init
前后的结果是否不同?如果是,则问题出在 cJSON 中。如果不是,则问题与 cJSON.
无关
我的猜测如下。 gtk_init
做了几件事,其中 sets locale。由于您从 .fr
域获取数据,我假设您的计算机上设置了法语区域设置。
to be exact, the parsing stops at the first decimal number and fail
在法语中,小数点分隔符是逗号,
而不是句点.
,所以我想在GTK+ 更改语言环境后,cJSON 开始寻找,
十进制数,但它找到 .
并失败。
可能的解决方案
作为解决方法,请在 gtk_init
之前调用 gtk_disable_setlocale
。这可能会导致意想不到的后果,例如。您的程序开始在 UI.
中以英语格式显示数字,而不是法语格式
真正的解决方案是在 cJSON 中引发错误,因为 JSON 解析数字时不应考虑语言环境。 JSON 要求句点 .
作为小数点分隔符。
我正在尝试用 GTK 开发一个 C 应用程序用于 GUI,libcurl 用于通过网络获取数据 API 和 cJSON 用于解析 JSON。
我的问题是,当我在 gtk_init 之后使用 libcurl 发出请求时,我得到的数据无法在 JSON 中解析。否则,如果我在 gtk_init 之前获取数据并解析它,解析工作正常。
我有一个例子来演示它,主要 returns 中的第一个 printf 和 JSON 正确但第二个 printf 在 gtk_init returns NULL (确切地说,解析在第一个十进制数处停止并失败):
初始化字符串:
void initString(String * s) {
s->len = 0;
s->ptr = malloc(s->len + 1);
if (s->ptr == NULL) {
fprintf(stderr, "malloc() failed\n");
exit(EXIT_FAILURE);
}
s->ptr[0] = '[=10=]';
}
写函数:
size_t writeFunc(void *ptr, size_t size, size_t nmemb, String * s)
{
size_t newLen = s->len + size*nmemb;
s->ptr = realloc(s->ptr, newLen + 1);
if (s->ptr == NULL) {
fprintf(stderr, "realloc() failed\n");
exit(EXIT_FAILURE);
}
memcpy(s->ptr + s->len, ptr, size * nmemb);
s->ptr[newLen] = '[=11=]';
s->len = newLen;
return size * nmemb;
}
我使用 libcurl 获取数据的函数:
char * getData(gpointer user_data)
{
curl_global_init(CURL_GLOBAL_ALL);
CURL * curl;
char * url = user_data;
CURLcode res;
String s;
struct curl_slist * headers = NULL;
curl = curl_easy_init();
if(curl)
{
initString(&s);
headers = curl_slist_append(headers, "Accept: application/json");
headers = curl_slist_append(headers, "Content-Type: application/json");
headers = curl_slist_append(headers, "charsets: utf-8");
//curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_easy_setopt(curl, CURLOPT_SSLVERSION, 6);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
//write data in a string
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunc);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
res = curl_easy_perform(curl);
}
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
return s.ptr;
}
主要 :
int main(int argc, char ** argv)
{
char * str;
cJSON * json;
str = getData("https://data.culture.gouv.fr/api/records/1.0/search/?dataset=liste-et-localisation-des-musees-de-france&facet=ville&sort=ville&facet=nomdep&refine.nomdep=AIN&rows=1");
json = cJSON_Parse(str);
printf("DATA : %s\n", cJSON_Print(json));//returns the JSON perfectly
gtk_init(&argc,&argv);
str = getData("https://data.culture.gouv.fr/api/records/1.0/search/?dataset=liste-et-localisation-des-musees-de-france&facet=ville&sort=ville&facet=nomdep&refine.nomdep=AIN&rows=1");
json = cJSON_Parse(str);
printf("ERROR : %s\n", cJSON_GetErrorPtr());//returns half of data
printf("DATA : %s\n", cJSON_Print(json));//returns NULL
gtk_main();
curl_global_cleanup();
return EXIT_SUCCESS;
}
我试图通过使用 g_idle_add、gdk_threads_idle_add、gdk_threads_entry 和 gdk_threads_leave、pthread_create 和 pthread_join 创建线程来解决这个问题但没有任何效果。
有人知道如何解决这个问题吗?
谢谢。
我非常怀疑这与 gtk_init() 调用有任何关系。这听起来像内存损坏。这可能是这种情况,例如如果您返回指向分配的数据的指针,然后由 curl 清理。在这种情况下,两次调用都是错误的,你只是碰巧第一次逃脱了它,因为在这种情况下,内存没有被触及。检查 API 是否有您进行的函数调用。有些会分配需要释放的内存,有些则不会。
我建议您使用带有-g 的构建并使用gdb 来测试您的代码。这将有助于缩小问题所在的范围。看看字符串是否相同。
cURL returns前后相同的数据,我通过将数据放入2个字符串和strcmp returns 0.
进行检查的确,我是法国人,,
和 .
之间可能存在混淆。
gtk_disable_setlocale
解决了我的问题!
您需要缩小问题范围。换句话说,你需要 "M" in MVCE。目前您拥有三个图书馆:
- Gtk+
- cURL
- cJSON
可能以任意方式进行交互。您需要检查的内容:
cURLreturn调用前后数据是否不同?如果不是,则问题不在于 cURL。
如果你在程序中硬编码JSON数据,然后用cJSON解析,
gtk_init
前后的结果是否不同?如果是,则问题出在 cJSON 中。如果不是,则问题与 cJSON. 无关
我的猜测如下。 gtk_init
做了几件事,其中 sets locale。由于您从 .fr
域获取数据,我假设您的计算机上设置了法语区域设置。
to be exact, the parsing stops at the first decimal number and fail
在法语中,小数点分隔符是逗号,
而不是句点.
,所以我想在GTK+ 更改语言环境后,cJSON 开始寻找,
十进制数,但它找到 .
并失败。
可能的解决方案
作为解决方法,请在
gtk_init
之前调用gtk_disable_setlocale
。这可能会导致意想不到的后果,例如。您的程序开始在 UI. 中以英语格式显示数字,而不是法语格式
真正的解决方案是在 cJSON 中引发错误,因为 JSON 解析数字时不应考虑语言环境。 JSON 要求句点
.
作为小数点分隔符。