Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way of referring to a C constant that was never defined/declared?

Tags:

c

redis

hiredis

I think the answer is no, and I usually don't have trouble going through source code, but I am slightly new to C/C++ and can't find where this constant is declared.

I am looking for CMD_REQ_REDIS_MGET in The hiredis-vip client library for Redis. I did a github/google search for this and got results in exactly two files for five occurrences. I also tried to grep for the string in the source code.

$ grep -rnw ./ -e "CMD_REQ_REDIS_MGET"
./command.c:241:    case CMD_REQ_REDIS_MGET:
./command.c:574:                    r->type = CMD_REQ_REDIS_MGET;
./hircluster.c:3257:        if (command->type == CMD_REQ_REDIS_MGET) {
./hircluster.c:3446:        if (command->type == CMD_REQ_REDIS_MGET) {
./hircluster.c:3480:    if (command->type == CMD_REQ_REDIS_MGET) {

The source code does not contain any binaries and is supposed to be self-contained. It doesn't include any libraries from external sources that are related to Redis, and so I have just been confused for a couple of hours.

The reason I need to know is that I am trying to add another constant just like it, and I keep getting errors that the declaration hasn't been found, so I am wondering if there is any black magic happening here with C that I am just not aware of.

EDIT: Wanted to point out that this code will in fact compile as is.

like image 450
Sidd Singal Avatar asked Dec 15 '17 21:12

Sidd Singal


1 Answers

It's not possible to use a constant that wasn't declared before. But in that case, the constant was declared, but not trivially.

You don't find the string anywhere (it should be in header files) because those values are defined in a macro from command.h using token pasting (## operator that creates new identifiers by combining old ones):

#define DEFINE_ACTION(_name) CMD_##_name,
typedef enum cmd_type {
    CMD_TYPE_CODEC(DEFINE_ACTION)
} cmd_type_t;
#undef DEFINE_ACTION

so you never find CMD_+your suffix. Then by some magic (the macro name is probably redefined at some point), the following defines all the elements:

#define CMD_TYPE_CODEC(ACTION)                                                                      \
    ACTION( UNKNOWN )                                                                               \
    ACTION( REQ_REDIS_DEL )                    /* redis commands - keys */                            \
    ACTION( REQ_REDIS_EXISTS )                                                                      \
    ACTION( REQ_REDIS_EXPIRE )                                                                      \
    ACTION( REQ_REDIS_EXPIREAT )                                                                    \
    ACTION( REQ_REDIS_PEXPIRE )                                                                     \
    ACTION( REQ_REDIS_PEXPIREAT )                                                                   \
    ACTION( REQ_REDIS_PERSIST )                                                                     \
    ACTION( REQ_REDIS_PTTL )                                                                        \
    ACTION( REQ_REDIS_SORT )                                                                        \
    ACTION( REQ_REDIS_TTL )          

Such macros are very useful to avoid copy/paste, but are hell when you're trying to find your way in the code using grep.

like image 54
Jean-François Fabre Avatar answered Nov 11 '22 17:11

Jean-François Fabre