我正在尝试将自己的包装函数编写到 libhiredis 以在我的项目中使用,但是当我尝试将redis_context传递到另一个函数以从那里发出命令时。代码段错误并通过 gdb 报告此问题:
GDB 错误:
Program received signal SIGSEGV, Segmentation fault.
sdscatlen (s=0x0, t=0x555555757690, len=22) at sds.c:239
239 sds.c: No such file or directory.
(gdb) backtrace
#0 sdscatlen (s=0x0, t=0x555555757690, len=22) at sds.c:239
#1 0x00007ffff7bcd300 in __redisAppendCommand (c=0x7fffffffddd0, cmd=<optimized out>, len=<optimized out>) at hiredis.c:910
#2 0x00007ffff7bcd38c in redisvAppendCommand (c=0x7fffffffddd0, format=<optimized out>, ap=<optimized out>) at hiredis.c:942
#3 0x00007ffff7bcd579 in redisvCommand (c=0x7fffffffddd0, format=<optimized out>, ap=ap@entry=0x7fffffffdcc0) at hiredis.c:1003
#4 0x00007ffff7bcd634 in redisCommand (c=<optimized out>, format=<optimized out>) at hiredis.c:1012
#5 0x0000555555554b9e in getnow (redis_context=0x7fffffffddd0) at src/testRedis.c:18
#6 0x0000555555554c14 in main () at src/testRedis.c:49
这是代码:
RedisWrapper.h:
#ifndef REDIS_WRAPPER_H
#define REDIS_WRAPPER_H
int redis_wrapper_init(redisContext *redis_context, char *ip, int port);
int redis_wrapper_set(redisContext *redis_context, char *key, char *value);
int redis_wrapper_get(redisContext *redis_context, char *key, char *retrieved_value);
#endif
RedisWrapper.c:
#include <hiredis.h>
int redis_wrapper_init(redisContext *redis_context, char* ip, int port) {
redis_context = redisConnect(ip, port);
if (redis_context == NULL || redis_context->err) {
if (redis_context) {
fprintf(stderr, "cget: redis init error: %sn", redis_context->errstr);
} else {
fprintf(stderr, "cget: can't allocate redis contextn");
}
return 1;
}
return 0;
}
int redis_wrapper_set(redisContext *redis_context, char *key, char *value) {
redisReply *reply = redisCommand(redis_context, "SET %s %s", key, value);
if(reply == NULL) {
fprintf(stderr, "cget: redis set error key: %s, val: %sn", key, value);
fprintf(stderr, "cget: redis set error: %sn", redis_context->errstr);
return 1;
}
freeReplyObject(reply);
return 0;
}
int redis_wrapper_get(redisContext *redis_context, char *key, char *retrieved_value) {
redisReply *reply = redisCommand(redis_context, "GET foo");
if(reply == NULL) {
fprintf(stderr, "cget: redis get error key: %sn", key);
fprintf(stderr, "cget: redis get error: %sn", redis_context->errstr);
return 1;
}
printf("GET: %sn", reply->str);
retrieved_value = reply->str;
freeReplyObject(reply);
return 0;
}
主.c
#include <stdio.h>
#include <string.h>
#include <hiredis.h>
#include "RedisWrapper.h"
void getnow(redisContext *redis_context) {
redisReply *reply = redisCommand(redis_context, "GET foo");
printf("GET foo: %sn", reply->str);
freeReplyObject(reply);
}
int main() {
redisContext *redis_context;
redis_wrapper_init(redis_context, "127.0.0.1", 6379);
getnow(redis_context);
return 0;
}
我的编译命令:
gcc -Wall -g -o src/redisTest src/RedisWrapper.c `pkg-config --cflags hiredis` src/Main.c `pkg-config --libs hiredis`
更多详情:
# uname -a
Linux node1 4.13.0-21-generic #24-Ubuntu SMP Mon Dec 17 17:29:16 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
# locate libhiredis
/usr/lib/x86_64-linux-gnu/libhiredis.a
/usr/lib/x86_64-linux-gnu/libhiredis.so
/usr/lib/x86_64-linux-gnu/libhiredis.so.0.13
/usr/share/doc/libhiredis-dbg
/usr/share/doc/libhiredis-dev
/usr/share/doc/libhiredis0.13
/usr/share/doc/libhiredis-dbg/changelog.Debian.gz
/usr/share/doc/libhiredis-dbg/copyright
/usr/share/doc/libhiredis-dev/README.md.gz
/usr/share/doc/libhiredis-dev/changelog.Debian.gz
/usr/share/doc/libhiredis-dev/copyright
/usr/share/doc/libhiredis0.13/changelog.Debian.gz
/usr/share/doc/libhiredis0.13/copyright
/var/cache/apt/archives/libhiredis-dbg_0.13.3-2_amd64.deb
/var/cache/apt/archives/libhiredis0.13_0.13.3-2_amd64.deb
/var/lib/dpkg/info/libhiredis-dbg:amd64.list
/var/lib/dpkg/info/libhiredis-dbg:amd64.md5sums
/var/lib/dpkg/info/libhiredis-dev:amd64.list
/var/lib/dpkg/info/libhiredis-dev:amd64.md5sums
/var/lib/dpkg/info/libhiredis0.13:amd64.list
/var/lib/dpkg/info/libhiredis0.13:amd64.md5sums
/var/lib/dpkg/info/libhiredis0.13:amd64.shlibs
/var/lib/dpkg/info/libhiredis0.13:amd64.symbols
/var/lib/dpkg/info/libhiredis0.13:amd64.triggers
我发现奇怪的是,如果我在 Main.c 中执行所有操作而不使用包装器文件,它就可以工作。不过,这对我的项目没有用,我需要能够传递redis_context并使其正常工作。
redis_wrapper_init
中的redis_context
应该通过引用传递(在 C 中通过指针传递(,以在调用此函数后保持赋值结果redis_context = redisConnect(ip, port);
。如果没有这个,您将 redisConnect 返回的指针分配给局部变量,当函数返回时,该变量将被销毁。
所以定义应该是
int redis_wrapper_init(redisContext ** redis_context, char* ip, int port) {
*redis_context = redisConnect(ip, port);
if (*redis_context == NULL || (*redis_context)->err) {
if (*redis_context) {
fprintf(stderr, "cget: redis init error: %sn", (*redis_context)->errstr);
}
...
}
}
在 main 中,您可以获取redis_context
变量的地址并将其传递给redis_wrapper_init
redisContext *redis_context = 0;
redis_wrapper_init(&redis_context, "127.0.0.1", 6379);