C语言 libhiredis 在将 redisContext 传递到另一个函数时不起作用



我正在尝试将自己的包装函数编写到 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);

相关内容

  • 没有找到相关文章