我正在开发一个 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);
// ...
}
虽然它有效,但并不完全是我想要的。我不想每次想发送单个通知时都分配/释放所有资源。因此我想在启动时打开连接,将模式设置为“RECONNECT”(这样它会在连接关闭后自动重新连接),并在程序终止时释放所有资源。
所以,如果我只是“外包”,例如将上下文
初始化为新函数时,出现段错误。这是我所做的:
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);
。它甚至不返回 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;
}
在 main 中,您可以将其称为 if(apn_ctx_init_wrapper(&ctx) != -1)
。
第二种方法是返回上下文,而不是返回 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;
}
在 main 中,您可以将其称为 if(NULL == (ctx = apn_ctx_init_wrapper()))
。当函数创建和初始化上下文时,无需将上下文传递给函数。
我更喜欢第二种方法。
关于C 段错误(Libcapn APNS 库),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38755132/