简体   繁体   中英

Concatenating a pointer to a string literal in a Macro

I need to append the function name of the caller concatenated wit brackets at the beginning of the string so it looks like [<FUNCTION_NAME>] <string> but rather I am getting [name] <string> as an output...possibly it has to do with # stringifying the variable passed in but how do you get it to work?

#define FUN(STR)                           "["#STR"] "

void foo(const char *name, char *fmt, ...)
{
    char buff[100] = {0};
    va_list pList;
    
    va_start(pList, fmt);
    int ret = vsprintf(buff, fmt, pList);
    va_end(pList);
    
    char p[100] = {0};
    sprintf (p, "%s%s", FUN(name), buff);
    printf ("%s\n", p);   // [name] Some string with value = 5
}

void bar()
{
    foo(__func__, "Some string with value = %d", 5);
}

int main() 
{
    bar();
    return 0;
}

Just put the brackets in printf format string.

printf("[%s]%s", name, buff)

But it sounds like a waste to have two buffers. Just have one buffer. Also, the code needs protection against overload. Needed checks need to be added to protect against overflowing the buffer. Also, prefer to use snprintf over sprintf .

#define MIN(a, b)  ((a)<(b)?(a):(b))

#ifdef __GNUC__
#if __GNUC__ > 10
__attribute__((__access__(read_only, 1)))
#endif
__attribute__((__format__(__printf__, 2, 3)))
#endif
void foo(const char *name, char *fmt, ...)
{
    char buff[10];
    char *p = buff;
    const char *const end = buff + sizeof(buff);
    // Add bracket.
    static_assert(sizeof(buff) > 0, "");
    *p++ = '[';
    // Add name.
    const size_t namelen = strlen(name);
    size_t free = end - p;
    // Leave space for 0 either way.
    const size_t tocopy = MIN(free - 1, namelen);
    memcpy(p, name, tocopy);
    p += tocopy;
    // Add "] ". Wonder, maybe it should be <=, not sure.
    if (p < end - 1) {
        *p++ = ']';
    }
    if (p < end - 1) {
        *p++ = ' ';
    }
    // Add printf stuff
    free = end - p;
    if (free > 1) {
        // It's odd that there is no vfoo(..., va_list va); overload.
        va_list va;
        va_start(va, fmt);
        const int r = vsnprintf(p, free + 1, fmt, va);
        va_end(va);
        (void)r;
        assert(r >= 0); // unneeded, pedantic: check errors
    } else {
        // Och, we remember about it.
        assert(p < end);
        *p = 0;
    }

    printf("%s\n", buff);
}

why would a macro approach not work?

In short: Macros work on text . Variables do not exist for preprocessor, only other macros. # applies # operation on text name , so it becomes "name" , in effect the call becomes;

sprintf (p, "%s%s", "[" "name" "] ", buff);

Adjacent "this" "that" string literals are concatenated together into one "thisthat" , and %s just prints it all.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM