首页 > 解决方案 > 在宏中连接指向字符串文字的指针

问题描述

我需要在字符串的开头附加调用方的函数名称并用括号连接,所以它看起来像[<FUNCTION_NAME>] <string>,但我得到[name] <string>的是输出......可能它与#字符串化传入的变量有关,但你怎么得到它工作吗?

#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;
}

标签: cstring

解决方案


只需将括号放在 printf 格式字符串中。

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

但是有两个缓冲区听起来很浪费。只要有一个缓冲区。此外,代码需要防止过载。需要添加所需的检查以防止缓冲区溢出。另外,更喜欢使用snprintfover 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);
}

为什么宏观方法不起作用?

简而言之:宏适用于text。预处理器不存在变量,只有其他宏。对text#应用#操作,所以它变成,实际上调用变成了; name"name"

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

相邻"this" "that"的字符串文字被连接在一起成为一个"thisthat",并%s打印出来。


推荐阅读