【问题标题】:Concatenating a pointer to a string literal in a Macro在宏中连接指向字符串文字的指针
【发布时间】:2021-09-30 01:24:20
【问题描述】:

我需要在字符串的开头附加调用方的函数名并用括号连接,这样它看起来像[<FUNCTION_NAME>] <string>,但我得到的是[name] <string>作为输出......可能它与@有关987654323@ 对传入的变量进行字符串化,但如何使其工作?

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

【问题讨论】:

  • 太棒了printf("[%s]%s", name, buff)?
  • 当然不是……
  • 为什么不呢?
  • 我只是不打印它;我想要一个指向它的指针,因为它在程序的其他地方使用过
  • 宏适用于 text,而不适用于变量,预处理器不存在变量。 #text name 应用 # 操作,因此它变为 "name"

标签: c string


【解决方案1】:

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

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

但是有两个缓冲区听起来很浪费。只要有一个缓冲区。此外,代码需要防止过载。需要添加所需的检查以防止缓冲区溢出。此外,更喜欢使用snprintf 而不是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 name 应用 # 操作,所以它变成 "name",实际上调用变成了;

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

相邻的"this" "that" 字符串字面量连接在一起形成一个"thisthat",而%s 则将其全部打印出来。

【讨论】:

  • " 有两个缓冲区听起来很浪费。"。我传入两个不同的参数并将它们组合成一个函数,因此有两个“缓冲区”。一旦字符串被连接,就会使用一个缓冲区。通过溢出缓冲区,您的意思是确保最多写入 99 个字节?还介意详细说明防止过载吗?不知道我是否明白了
  • I am passing in two different params and combining them into a function hence two "buffers". Once the string is concat'd, one buffer is used 从一开始就使用一个缓冲区。 you meant to make sure a max of 99 bytes are written? 是的。 Also mind elaborating on protecting我不明白..逻辑是:if (characters_written &gt;= sizeof(buff)) { do_not_write_more_characters_to_buff(); { else { continue_writing_more_characters_to_buff(); }
猜你喜欢
  • 1970-01-01
  • 2013-04-26
  • 2021-06-28
  • 2011-04-12
  • 1970-01-01
  • 1970-01-01
  • 2019-01-15
  • 1970-01-01
相关资源
最近更新 更多