C 段错误(Libcapn APNS 库)
C Segmentation Fault (Libcapn APNS Library)
我正在开发一个 C 程序,它使用 Libcapn 库 (http://libcapn.org) 连接到 Apple 的推送通知服务并发送推送通知。
网站上显示的示例工作正常,我可以用它向我的 iPhone 发送推送通知。
现在我要把它集成到我现有的程序中,以便向我的 iPhone 发送更具体的通知,但是当我尝试将代码拆分为多个函数时,我总是遇到分段错误。
示例:在给定的代码中,一切都发生在 main
函数中:
int main() {
apn_payload_t *payload = NULL;
apn_ctx_t *ctx = NULL;
time_t time_now = 0;
char *invalid_token = NULL;
// ...
if(NULL == (ctx = apn_init())) {
printf("Unable to init context: %d\n", errno);
apn_library_free();
return -1;
}
apn_set_pkcs12_file(ctx, "my-certificate.p12", "my4711passphrase");
apn_set_mode(ctx, APN_MODE_SANDBOX); //APN_MODE_PRODUCTION or APN_MODE_SANDBOX
apn_set_behavior(ctx, APN_OPTION_RECONNECT);
apn_set_log_level(ctx, APN_LOG_LEVEL_INFO | APN_LOG_LEVEL_ERROR | APN_LOG_LEVEL_DEBUG);
apn_set_log_callback(ctx, __apn_logging);
apn_set_invalid_token_callback(ctx, __apn_invalid_token);
// ...
}
虽然它有效,但这并不是我想要的。我不想每次发送单个通知时都 allocate/free 所有资源。因此我想在启动时打开连接,将模式设置为 "RECONNECT"(以便在连接关闭后自动重新连接)并在程序终止时释放所有资源。
所以如果我 "outsource" 例如将 context
初始化为新函数时,出现分段错误。这是我所做的:
int apn_ctx_init_wrapper(apn_ctx_t *ctx) {
if(NULL == (ctx = apn_init())) {
printf("Unable to init context: %d\n", errno);
apn_library_free();
return -1;
}
apn_set_pkcs12_file(ctx, "my-certificate.p12", "my4711passphrase");
apn_set_mode(ctx, APN_MODE_SANDBOX); //APN_MODE_PRODUCTION or APN_MODE_SANDBOX
apn_set_behavior(ctx, APN_OPTION_RECONNECT);
apn_set_log_level(ctx, APN_LOG_LEVEL_INFO | APN_LOG_LEVEL_ERROR | APN_LOG_LEVEL_DEBUG);
apn_set_log_callback(ctx, __apn_logging);
apn_set_invalid_token_callback(ctx, __apn_invalid_token);
return 0;
}
... 我将上面的代码替换为单个函数调用,如 apn_ctx_init_wrapper(ctx);
。它甚至没有 return 0
或 -1
。当函数 get 被调用时,我得到了一个段错误。为什么?请帮助我!
这是按值传递指针并尝试将指针的本地副本指向新位置的经典案例。原来的指针留在原来的位置。
我会给你两种处理这种情况的方法。
您可以修改该函数,使其接受指针的地址。
int apn_ctx_init_wrapper(apn_ctx_t **ctx) {
if(NULL == (*ctx = apn_init())) { //Note that the pointer needs to be dereferenced
printf("Unable to init context: %d\n", errno);
apn_library_free();
return -1;
}
apn_set_pkcs12_file(*ctx, "my-certificate.p12", "my4711passphrase");
apn_set_mode(*ctx, APN_MODE_SANDBOX); //APN_MODE_PRODUCTION or APN_MODE_SANDBOX
apn_set_behavior(*ctx, APN_OPTION_RECONNECT);
apn_set_log_level(*ctx, APN_LOG_LEVEL_INFO | APN_LOG_LEVEL_ERROR | APN_LOG_LEVEL_DEBUG);
apn_set_log_callback(*ctx, __apn_logging);
apn_set_invalid_token_callback(*ctx, __apn_invalid_token);
return 0;
}
在主要部分,您可以将其称为 if(apn_ctx_init_wrapper(&ctx) != -1)
。
第二种方法是 return 上下文而不是 returning 0
或 -1
.
apn_ctx_t *apn_ctx_init_wrapper() {
apn_ctx_t *ctx;
if(NULL == (ctx = apn_init())) {
printf("Unable to init context: %d\n", errno);
apn_library_free();
return NULL;
}
apn_set_pkcs12_file(ctx, "my-certificate.p12", "my4711passphrase");
apn_set_mode(ctx, APN_MODE_SANDBOX); //APN_MODE_PRODUCTION or APN_MODE_SANDBOX
apn_set_behavior(ctx, APN_OPTION_RECONNECT);
apn_set_log_level(ctx, APN_LOG_LEVEL_INFO | APN_LOG_LEVEL_ERROR | APN_LOG_LEVEL_DEBUG);
apn_set_log_callback(ctx, __apn_logging);
apn_set_invalid_token_callback(ctx, __apn_invalid_token);
return ctx;
}
一个主要的你可以称它为if(NULL == (ctx = apn_ctx_init_wrapper()))
。无需将上下文传递给函数,因为函数正在创建和初始化上下文。
我更喜欢第二种方法
我正在开发一个 C 程序,它使用 Libcapn 库 (http://libcapn.org) 连接到 Apple 的推送通知服务并发送推送通知。
网站上显示的示例工作正常,我可以用它向我的 iPhone 发送推送通知。
现在我要把它集成到我现有的程序中,以便向我的 iPhone 发送更具体的通知,但是当我尝试将代码拆分为多个函数时,我总是遇到分段错误。
示例:在给定的代码中,一切都发生在 main
函数中:
int main() {
apn_payload_t *payload = NULL;
apn_ctx_t *ctx = NULL;
time_t time_now = 0;
char *invalid_token = NULL;
// ...
if(NULL == (ctx = apn_init())) {
printf("Unable to init context: %d\n", errno);
apn_library_free();
return -1;
}
apn_set_pkcs12_file(ctx, "my-certificate.p12", "my4711passphrase");
apn_set_mode(ctx, APN_MODE_SANDBOX); //APN_MODE_PRODUCTION or APN_MODE_SANDBOX
apn_set_behavior(ctx, APN_OPTION_RECONNECT);
apn_set_log_level(ctx, APN_LOG_LEVEL_INFO | APN_LOG_LEVEL_ERROR | APN_LOG_LEVEL_DEBUG);
apn_set_log_callback(ctx, __apn_logging);
apn_set_invalid_token_callback(ctx, __apn_invalid_token);
// ...
}
虽然它有效,但这并不是我想要的。我不想每次发送单个通知时都 allocate/free 所有资源。因此我想在启动时打开连接,将模式设置为 "RECONNECT"(以便在连接关闭后自动重新连接)并在程序终止时释放所有资源。
所以如果我 "outsource" 例如将 context
初始化为新函数时,出现分段错误。这是我所做的:
int apn_ctx_init_wrapper(apn_ctx_t *ctx) {
if(NULL == (ctx = apn_init())) {
printf("Unable to init context: %d\n", errno);
apn_library_free();
return -1;
}
apn_set_pkcs12_file(ctx, "my-certificate.p12", "my4711passphrase");
apn_set_mode(ctx, APN_MODE_SANDBOX); //APN_MODE_PRODUCTION or APN_MODE_SANDBOX
apn_set_behavior(ctx, APN_OPTION_RECONNECT);
apn_set_log_level(ctx, APN_LOG_LEVEL_INFO | APN_LOG_LEVEL_ERROR | APN_LOG_LEVEL_DEBUG);
apn_set_log_callback(ctx, __apn_logging);
apn_set_invalid_token_callback(ctx, __apn_invalid_token);
return 0;
}
... 我将上面的代码替换为单个函数调用,如 apn_ctx_init_wrapper(ctx);
。它甚至没有 return 0
或 -1
。当函数 get 被调用时,我得到了一个段错误。为什么?请帮助我!
这是按值传递指针并尝试将指针的本地副本指向新位置的经典案例。原来的指针留在原来的位置。
我会给你两种处理这种情况的方法。
您可以修改该函数,使其接受指针的地址。
int apn_ctx_init_wrapper(apn_ctx_t **ctx) {
if(NULL == (*ctx = apn_init())) { //Note that the pointer needs to be dereferenced
printf("Unable to init context: %d\n", errno);
apn_library_free();
return -1;
}
apn_set_pkcs12_file(*ctx, "my-certificate.p12", "my4711passphrase");
apn_set_mode(*ctx, APN_MODE_SANDBOX); //APN_MODE_PRODUCTION or APN_MODE_SANDBOX
apn_set_behavior(*ctx, APN_OPTION_RECONNECT);
apn_set_log_level(*ctx, APN_LOG_LEVEL_INFO | APN_LOG_LEVEL_ERROR | APN_LOG_LEVEL_DEBUG);
apn_set_log_callback(*ctx, __apn_logging);
apn_set_invalid_token_callback(*ctx, __apn_invalid_token);
return 0;
}
在主要部分,您可以将其称为 if(apn_ctx_init_wrapper(&ctx) != -1)
。
第二种方法是 return 上下文而不是 returning 0
或 -1
.
apn_ctx_t *apn_ctx_init_wrapper() {
apn_ctx_t *ctx;
if(NULL == (ctx = apn_init())) {
printf("Unable to init context: %d\n", errno);
apn_library_free();
return NULL;
}
apn_set_pkcs12_file(ctx, "my-certificate.p12", "my4711passphrase");
apn_set_mode(ctx, APN_MODE_SANDBOX); //APN_MODE_PRODUCTION or APN_MODE_SANDBOX
apn_set_behavior(ctx, APN_OPTION_RECONNECT);
apn_set_log_level(ctx, APN_LOG_LEVEL_INFO | APN_LOG_LEVEL_ERROR | APN_LOG_LEVEL_DEBUG);
apn_set_log_callback(ctx, __apn_logging);
apn_set_invalid_token_callback(ctx, __apn_invalid_token);
return ctx;
}
一个主要的你可以称它为if(NULL == (ctx = apn_ctx_init_wrapper()))
。无需将上下文传递给函数,因为函数正在创建和初始化上下文。
我更喜欢第二种方法