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

1

5

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.

Dither answered 15/12, 2017 at 21:17 Comment(2)
are you sure you're performing the grep at the proper level? such definitions are usually in the .h file.Jeuz
@Jean-FrançoisFabre I am performing it at the root of the git repoDither
E
10

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.

Eratosthenes answered 15/12, 2017 at 21:22 Comment(3)
Oh man, did not know something like that could be possible.. I'll do more research on C macros. I really appreciate you looking into this for me! (I'll accept as soon as I am allowed to)Dither
## is the token-pasting operator. A single # character (not used here) is the stringifying (not "stringing") operator (I don't think the standard uses that term).Wellfavored
@SiddSingal, C macros and cpp macro processor is something exploited too much in the past, enough to be present in C++, which doesn't need macros at all (at least since the templates were incorporated to the language) and continues to be used today. It was conceived as a plain text macro package, so you will se some weird "as text" uses of it, like the one discussed in this response.Bunyabunya

© 2022 - 2024 — McMap. All rights reserved.