【问题标题】:Help gcc to not warn about not using a string literal format string帮助 gcc 不警告不使用字符串文字格式字符串
【发布时间】:2009-08-27 16:27:29
【问题描述】:

我正在用 C 语言创建一个函数来将索引值转换为字符串,这是对索引所代表的“字段”的详细描述。

所以,我有一个很好的数组,其中包含索引的所有详细描述,以及索引。

要将其转储到缓冲区中,我使用这样的代码

#define BUFFER_SIZE 40
void format_verbose(uint32_t my_index,
                    char     my_buffer[BUFFER_SIZE])
  {
    snprintf(mY_buffer, BUFFER_SIZE, "%s", MY_ARRAY[my_index].description);
  }

问题出现在某些情况下,我需要在格式化字符串时将一些其他字符串插入到字符串中。所以我想要的是这样的(在这种情况下,描述包含%s)。

void format_verbose_with_data(uint32_t my_index,
                              char     my_buffer[BUFFER_SIZE])
  {
    // ...
    snprintf(mY_buffer, BUFFER_SIZE, MY_ARRAY[my_index].description,
             some_string);
  }

我们的 make 文件设置为使 snprintf() 的这种(危险)使用警告,并且警告被视为错误。所以,它不会编译。我想关闭这一行的警告,虽然它有点危险,但我会控制字符串,并且我可以测试以确保它适用于调用它的每个值。

或者,我很乐意以其他方式执行此操作,但我真的不热衷于使用此解决方案

void format_verbose_with_data(uint32_t my_index,
                              char     my_buffer[BUFFER_SIZE])
  {
    // ...
    snprintf(mY_buffer, BUFFER_SIZE, "%s%s%s"
    MY_ARRAY[my_index].description1, some_string,
    MY_ARRAY[my_index].description2);
  }

因为它使我的描述数组变得丑陋,尤其是对于那些我不需要添加额外值的数组。

【问题讨论】:

    标签: c gcc printf


    【解决方案1】:

    GCC 无法逐行关闭警告,所以我怀疑你不走运。无论如何,如果你的编码标准说你不应该做某事,你就不应该寻找打败它们的方法。

    还有一点,当你说:

    void format_verbose(uint32_t my_index,
                        char     my_buffer[BUFFER_SIZE])
    

    你真的是在浪费时间打字——这样说更清楚也更惯用:

    void format_verbose(uint32_t my_index,
                        char     my_buffer[])
    

    或:

    void format_verbose(uint32_t my_index,
                        char     * my_buffer)
    

    【讨论】:

    • 可能是 C 对传入的缓冲区大小没有提供任何保护,但我不同意将缓冲区大小留出更清楚,当您可以清楚地看到代码假定它是正确的。旁观者认为清晰 :-) OTH,我可能应该保护自己免受短缓冲区的影响,无论是定义错误行为还是断言。编码标准问题的一个例子是类型转换 - 我们允许它们防止编译器警告,这使得正在发生的事情更加明显。
    【解决方案2】:

    如果你对snprintf() 所做的只是复制字符串(似乎是这样),即你所拥有的只是一个或多个"%s" 作为格式字符串,你为什么不使用strcpy(),也许先使用strlen() 来检查源的长度?

    请注意,strncpy() 虽然看起来是个好主意,但实际上并非如此。它总是用零填充目标缓冲区,如果源超出缓冲区大小,不会以空值终止字符串

    【讨论】:

    • 感谢您的回答!我很久以前就放弃了这项工作:-(。无论如何,我不确定这两个函数之间有多大区别。复制或打印,我仍然想在字符串中间“插入”一些东西,所以对我来说,我喜欢 snprintf() 解决方案的最终结果。
    【解决方案3】:

    经过一夜的思考,我计划手动分割输入字符串,通过自己查找 %s 标记,然后将字符串 separetley 发送到带有自己的 %s 的 snprintf() 中。对于这种情况,只允许使用一种类型的格式字符串,这不那么繁琐,但是尝试完全重新实现 printf() 样式解析器会很糟糕。

    void format_verbose_with_data(uint32_t my_index,
                                  char     my_buffer[BUFFER_SIZE])
      {
        char    pre_description[BUFFER_SIZE];
        char    post_description[BUFFER_SIZE];
        int32_t offset = -1;
    
        offset = find_string(MY_ARRAY[my_index].description, "%s");
        ASSERT(offset >=0, "No split location!");
        // Use offset to copy the pre and post descriptions
        // Exercise left to the reader :-)
        snprintf(mY_buffer, BUFFER_SIZE, "%s%s%s"
                 pre_description, some_string, post_description);
      }
    

    【讨论】:

    • 已编辑以删除检查字符串缓冲区长度的愚蠢尝试。当然那是行不通的,除非缓冲区被初始化为非零。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 2010-12-13
    • 2011-05-24
    相关资源
    最近更新 更多