www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Problem with Hiredis Binding

reply Puming Zhao <zhaopuming gmail.com> writes:
Hi, I'm new in D programming, and does not have much C experience either.  After
reading TDPL book and playing with some sample codes, I came to decide to try
something more `practical`. I began with a Redis client binding from Hiredis C
code.
Hiredis is a small lib, and seems very simple to bind to D.

My code on github:

https://github.com/zhaopuming/dredis

But I went into problems that I don't know how to solve. When running example.d
I
went into segment fault, and can't get redisReply from a redis command. I tried
to
google it but got nothing.

So my question is, could some one with more knowledge in redis or C/D look into
my
code and see what's wrong ? Or is there already a Redis binding exists?
Jan 05 2012
next sibling parent reply Joshua Reusch <yoschi arkandos.de> writes:
Am 05.01.2012 17:21, schrieb Puming Zhao:
 Hi, I'm new in D programming, and does not have much C experience either. 
After
 reading TDPL book and playing with some sample codes, I came to decide to try
 something more `practical`. I began with a Redis client binding from Hiredis C
code.
 Hiredis is a small lib, and seems very simple to bind to D.

 My code on github:

 https://github.com/zhaopuming/dredis

 But I went into problems that I don't know how to solve. When running
example.d I
 went into segment fault, and can't get redisReply from a redis command. I
tried to
 google it but got nothing.

 So my question is, could some one with more knowledge in redis or C/D look
into my
 code and see what's wrong ? Or is there already a Redis binding exists?

dredis.d:
 redisContext* redisConnectWithTimeout(const char* ip, int port, 

example.d:
 redisConnectWithTimeout("127.0.0.1", 6379, timeout);

D strings do not end with an \0 byte ! You can use std.string.toStringz to convert them to C's const char* -- Joshua
Jan 05 2012
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 01/05/2012 07:14 PM, Joshua Reusch wrote:
 Am 05.01.2012 17:21, schrieb Puming Zhao:
 Hi, I'm new in D programming, and does not have much C experience
 either. After
 reading TDPL book and playing with some sample codes, I came to decide
 to try
 something more `practical`. I began with a Redis client binding from
 Hiredis C code.
 Hiredis is a small lib, and seems very simple to bind to D.

 My code on github:

 https://github.com/zhaopuming/dredis

 But I went into problems that I don't know how to solve. When running
 example.d I
 went into segment fault, and can't get redisReply from a redis
 command. I tried to
 google it but got nothing.

 So my question is, could some one with more knowledge in redis or C/D
 look into my
 code and see what's wrong ? Or is there already a Redis binding exists?

dredis.d: > redisContext* redisConnectWithTimeout(const char* ip, int port, timeval tv); example.d: > redisConnectWithTimeout("127.0.0.1", 6379, timeout); D strings do not end with an \0 byte ! You can use std.string.toStringz to convert them to C's const char* -- Joshua

D string literals are zero-terminated.
Jan 05 2012
parent reply Joshua Reusch <yoschi arkandos.de> writes:
Am 05.01.2012 19:44, schrieb Timon Gehr:
 On 01/05/2012 07:14 PM, Joshua Reusch wrote:
 Am 05.01.2012 17:21, schrieb Puming Zhao:
 Hi, I'm new in D programming, and does not have much C experience
 either. After
 reading TDPL book and playing with some sample codes, I came to decide
 to try
 something more `practical`. I began with a Redis client binding from
 Hiredis C code.
 Hiredis is a small lib, and seems very simple to bind to D.

 My code on github:

 https://github.com/zhaopuming/dredis

 But I went into problems that I don't know how to solve. When running
 example.d I
 went into segment fault, and can't get redisReply from a redis
 command. I tried to
 google it but got nothing.

 So my question is, could some one with more knowledge in redis or C/D
 look into my
 code and see what's wrong ? Or is there already a Redis binding exists?

dredis.d:
 redisContext* redisConnectWithTimeout(const char* ip, int port,

example.d:
 redisConnectWithTimeout("127.0.0.1", 6379, timeout);

D strings do not end with an \0 byte ! You can use std.string.toStringz to convert them to C's const char* -- Joshua

D string literals are zero-terminated.

Sure ? dlang.org says they are not: http://www.d-programming-language.org/arrays.html#strings
Jan 05 2012
parent reply Joshua Reusch <yoschi arkandos.de> writes:
 Sure ? dlang.org says they are not:
 http://www.d-programming-language.org/arrays.html#strings

Sorry, in the printf section: "String literals already have a 0 appended to them, so can be used directly" I missed this.
Jan 05 2012
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Andrej Mitrovic:

 I think `long long` in C is 8 bytes, which is the
 equivalent to D's long type.

I think C just requires: sizeof(long long int) >= sizeof(long int). For the actual size I think you have to ask to the C compiler. Bye, bearophile
Jan 05 2012
prev sibling parent reply Mike Parker <aldacron gmail.com> writes:
On 1/6/2012 11:38 AM, Puming wrote:
 On Thursday, 5 January 2012 at 22:02:25 UTC, Andrej Mitrovic wrote:

 Your problem is that you're calling printf on a static char array. If
 you're going to use printf you have to use it on the .ptr (pointer)
 field of the static array. Replace this call:

 printf("Connection error: %s\n", c.errstr);
 with
 printf("Connection error: %s\n", c.errstr.ptr);

 On my end I get:
 Connection error: Connection refused

 Also I think you should replace the "int integer" in struct redisReply
 to "long integer". I think `long long` in C is 8 bytes, which is the
 equivalent to D's long type.

Thanks for the tip. I've changed code as you suggested. And for the type `long long`, I changed `int` to `c_long` (in core.stdc.config) according to http://dlang.org/interfaceToC.html But there is still problem. My code does actually connect, as I have a redis-server running on my machine, and the commands actually runned, as I use a redis-cli and found that "foo : bar" is actually set into redis. But --- reply = cast(redisReply*) redisCommand(c, "GET foo"); writefln("GET foo: %s", *reply); writefln(to!string(reply.str)); ---- output these: --- GET foo: redisReply(1, 0, 0, 2, 152397072, 0) 80B1F42 段错误 // (which is Chinese for Segfault) --- So maybe I got it wrong when converting char* to string?

I think the problem still lies with your declaration of the integer field. c_long in D is supposed to be equivalent to the long type in C, *not* long long. It is declared as 32 bits on a 32-bit system and 64 bits on a 64-bit system. I believe that in practice, most C compilers implement long long as 64 bits on both 32- and 64-bit systems. I recommend you use long on the D side, rather than c_long. And, actually, it would be best to compile a test with the same C compiler used to compile redis to verify the size of long long.
Jan 05 2012
next sibling parent reply Mike Parker <aldacron gmail.com> writes:
On 1/6/2012 2:34 PM, Puming wrote:

equivalent to `long long` in C. Is this wrong?

Well, either the documentation is wrong or the implementation is. Looks like one for Bugzilla.
Jan 06 2012
parent Johannes Pfau <spam example.com> writes:
Mike Parker wrote:

 On 1/6/2012 2:34 PM, Puming wrote:

equivalent to `long long` in C. Is this wrong?

Well, either the documentation is wrong or the implementation is. Looks like one for Bugzilla.

The documentation is wrong. c_long is meant to be used _only_ for C's "long" type, so it must be 32bit for 32bit architectures and 64bit for (most) 64bit architectures. See also: http://en.wikipedia.org/wiki/64-bit#64- bit_data_models No need to file a bug though, I posted a fix here: https://github.com/D- Programming-Language/d-programming-language.org/pull/55
Jan 06 2012
prev sibling parent bearophile <bearophileHUGS lycos.com> writes:
Puming:

 1. "long long" in C is always 64bit, so in D it's "long";

In C "long long" isn't always 64 bit. Bye, bearophile
Jan 06 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
Your problem is that you're calling printf on a static char array. If
you're going to use printf you have to use it on the .ptr (pointer)
field of the static array. Replace this call:

    printf("Connection error: %s\n", c.errstr);
with
    printf("Connection error: %s\n", c.errstr.ptr);

On my end I get:
Connection error: Connection refused

Also I think you should replace the "int integer" in struct redisReply
to "long integer". I think `long long` in C is 8 bytes, which is the
equivalent to D's long type.
Jan 05 2012
prev sibling next sibling parent "Puming" <zhaopuming gmail.com> writes:
On Thursday, 5 January 2012 at 22:02:25 UTC, Andrej Mitrovic 
wrote:

 Your problem is that you're calling printf on a static char 
 array. If
 you're going to use printf you have to use it on the .ptr 
 (pointer)
 field of the static array. Replace this call:

   printf("Connection error: %s\n", c.errstr);
 with
   printf("Connection error: %s\n", c.errstr.ptr);

 On my end I get:
 Connection error: Connection refused

 Also I think you should replace the "int integer" in struct 
 redisReply
 to "long integer". I think `long long` in C is 8 bytes, which 
 is the
 equivalent to D's long type.

Thanks for the tip. I've changed code as you suggested. And for the type `long long`, I changed `int` to `c_long` (in core.stdc.config) according to http://dlang.org/interfaceToC.html But there is still problem. My code does actually connect, as I have a redis-server running on my machine, and the commands actually runned, as I use a redis-cli and found that "foo : bar" is actually set into redis. But --- reply = cast(redisReply*) redisCommand(c, "GET foo"); writefln("GET foo: %s", *reply); writefln(to!string(reply.str)); ---- output these: --- GET foo: redisReply(1, 0, 0, 2, 152397072, 0) 80B1F42 段错误 // (which is Chinese for Segfault) --- So maybe I got it wrong when converting char* to string?
Jan 05 2012
prev sibling next sibling parent "Puming" <zhaopuming gmail.com> writes:
 I think the problem still lies with your declaration of the 
 integer field. c_long in D is supposed to be equivalent to the 
 long type in C, *not* long long. It is declared as 32 bits on a 
 32-bit system and 64 bits on a 64-bit system. I believe that in 
 practice, most C compilers implement long long as 64 bits on 
 both 32- and 64-bit systems. I recommend you use long on the D 
 side, rather than c_long. And, actually, it would be best to 
 compile a test with the same C compiler used to compile redis 
 to verify the size of long long.

I changed c_long to long and it actually works !!! Thanks very much. Now I'm wondering should I use `long` or do some static check for the type just like what c_long does for C' long type? I'm only using 32bit Ubuntu, so not able to check this on other systems. Wonder whether there is a c_long_long type. In http://dlang.org/interfaceToC.html it says in 32bit system c_long is equivalent to `long long` in C. Is this wrong?
Jan 05 2012
prev sibling next sibling parent "Puming" <zhaopuming gmail.com> writes:
Here is what I've got so far:

1. "long long" in C is always 64bit, so in D it's "long";
2. C's char* string should be converted to!string when used in 
"writeln";
3. String literals in D -IS- zero terminated;

And now it's working fine. Thanks everybody :)
Jan 05 2012
prev sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 1/6/12, Johannes Pfau <spam example.com> wrote:
 The documentation is wrong.

That was my fault. I was going to fix the original docs which had no mention of c_long/c_ulong and I ended up screwing up the tables. Sorry!
Jan 06 2012
prev sibling parent reply Johannes Pfau <spam example.com> writes:
Puming Zhao wrote:

 Hi, I'm new in D programming, and does not have much C experience either. 
 After reading TDPL book and playing with some sample codes, I came to
 decide to try something more `practical`. I began with a Redis client
 binding from Hiredis C code. Hiredis is a small lib, and seems very simple
 to bind to D.
 
 My code on github:
 
 https://github.com/zhaopuming/dredis
 
 But I went into problems that I don't know how to solve. When running
 example.d I went into segment fault, and can't get redisReply from a redis
 command. I tried to google it but got nothing.
 
 So my question is, could some one with more knowledge in redis or C/D look
 into my code and see what's wrong ? Or is there already a Redis binding
 exists?

in hiredis.d ------------------------ struct redisReply { int type; /* REDIS_REPLY_* */ int integer; /* The integer when type is REDIS_REPLY_INTEGER */ int len; /* Length of string */ char* str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */ size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */ redisReply** element; /* elements vector for REDIS_REPLY_ARRAY */ }; ------------------------ but in hiredis.h ------------------------ typedef struct redisReply { int type; /* REDIS_REPLY_* */ long long integer; /* The integer when type is REDIS_REPLY_INTEGER */ int len; /* Length of string */ char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */ size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */ struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */ } redisReply; ------------------------ So you have "int integer;" in D and "long long integer;" in C, which doesn't match. I'm not sure what size "long long" is in C, but I guess you need "long" in D?
Jan 05 2012
parent "Puming" <zhaopuming gmail.com> writes:
 So you have "int integer;" in D and "long long integer;" in C, 
 which doesn't match. I'm not sure what size "long long" is in 
 C, but I guess you need "long" in D?

Thanks. I've changed `int integer` to `c_long integer` according to this page http://dlang.org/interfaceToC.html c_long is in core.stdc.config But I still can not get reply.str right...
Jan 05 2012