将redisContext传递给另一个函数时,libhiredis不起作用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将redisContext传递给另一个函数时,libhiredis不起作用相关的知识,希望对你有一定的参考价值。

我正在尝试将自己的包装函数写入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: %s\n", redis_context->errstr);
        } else {
            fprintf(stderr, "cget: can't allocate redis context\n");
        }
        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: %s\n", key, value);
        fprintf(stderr, "cget: redis set error: %s\n", 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: %s\n", key);
        fprintf(stderr, "cget: redis get error: %s\n", redis_context->errstr);
        return 1;
    }

    printf("GET: %s\n", reply->str);
    retrieved_value = reply->str;
    freeReplyObject(reply);

    return 0;

}

MAIN.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: %s\n", 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_context中的redis_wrapper_init应该通过引用(在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: %s\n", (*redis_context)->errstr);
      }
      ...
  }
}

在主要你得到redis_context变量的地址,并将其传递给redis_wrapper_init

redisContext *redis_context = 0;
redis_wrapper_init(&redis_context, "127.0.0.1", 6379);

以上是关于将redisContext传递给另一个函数时,libhiredis不起作用的主要内容,如果未能解决你的问题,请参考以下文章

如何在 STL 中使用指向向量的指针,就像我们在将数组地址传递给另一个函数时将指针分配给数组一样?

如何将关键部分传递给另一个线程?

JavaScript 将作用域传递给另一个函数

Llvm C++ API 将指向函数的指针传递给另一个函数

将多个值传递给另一个函数内的函数

将变量传递给另一个页面上的函数