【问题标题】:Proper way to replace string prefix in C在C中替换字符串前缀的正确方法
【发布时间】:2021-02-08 18:54:30
【问题描述】:

我的目标是替换字符串中的前n (3) 个字符,而不会收到任何编译器警告或触发未定义的行为:

const char *replacment = "abc";
char buffer[128] = "xxx-remainder";

我正在使用 gcc (GCC) 9.2.0 和标准库:

  1. 使用 sprintf 似乎是在 replacement 中插入 NUL 字符,即使我认为我告诉它不要这样做:

    sprintf(buffer, "%.3s", replacement);
    printf("%s\n", buffer);   /// prints "abc", not "abc-remainder"
    
  2. 使用strncpy 会引发警告:

    strncpy(buffer, replacement, 3);
    

    这会触发以下警告:

    test.c: In function 'main':
    main.c:8:5: warning: 'strncpy' output truncated before terminating nul copying 3 bytes from a string of the same length [-Wstringop-truncation]
     8 |         strncpy(buffer, replacement, 3);
       |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~
    

    在这种情况下,输出看起来很好。

  3. 当然,我可以使用for 循环手动复制字符,但我会尽量避免这种情况。

如何修复此处显示的任何一种方法,或者什么替代函数调用可以让我替换前 3 个字符而不在字符串中插入 NUL 或收到警告?

【问题讨论】:

    标签: c copy c-strings


    【解决方案1】:
    memcpy(buffer, replacement, strlen(replacement));
    

    就是你要找的。​​p>

    另一种(非常模糊的)方式:

    char c = buffer[strlen(replacement)];
    buffer[snprintf(buffer, sizeof buffer, "%s", replacement)] = c;
    

    【讨论】:

    • 我认为 +1 是额外的。我特别想不插入尾随'\0'
    • 哎呀,让我检查一下
    • 您对sprintf 格式了解得足够多,可以修复我原来的方法吗?
    • 对不起,@MadPhysicist,我能与sprintf 和朋友最接近的是buffer[snprintf(buffer, sizeof buffer, "%s", replacement)] = c;,你不能和他们一起跳过尾随的NUL。
    • 哇。我已经盯着它看了一段时间了。终于意识到我的格式规范很好。这不是 NUL 的来源:)
    【解决方案2】:

    只需使用 memcpy。

    memcpy( buffer, replacement, 3 );
    

    这是一个演示程序。

    #include <stdio.h>
    #include <string.h>
    
    int main(void) 
    {
        const char *replacment = "abc";
        char buffer[128] = "xxx-remainder";
        
        printf( "%s\n", ( char * )memcpy( buffer, replacment, strlen( replacment ) ) );
        
        return 0;
    }
    

    程序输出是

    abc-remainder
    

    【讨论】:

      【解决方案3】:

      将字符数设为变量可使strncpy 方法在没有警告的情况下工作:

      const char *replacment = "abc";
      char buffer[128] = "xxx-remainder";
      
      const int n = 3;
      strncpy(buffer, replacement, n);
      

      const 限定符是可选的。

      显然警告是 9.0 版中的一个错误:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87028,随后被修复。大概在 9.2 到 10.2 之间。

      【讨论】:

      • 奇怪,我正在使用 gcc 并警告包括 Wstringop-truncation:gcc -std=c11 -Wpedantic -Wall -Wextra -Wstringop-truncation strncpy(buffer, replacement, 3); 没有给出任何警告。如果重要的话,我在 Ubuntu 20.04 上。 gcc 10.2.0
      • @DavidRanieri。奇怪的。那么它可能严重依赖版本。无论如何,这似乎是一件奇怪的事情。
      • @DavidRanieri。感谢您指出。我做了一些挖掘,显然这是在版本 9 和 10 之间修复的错误。我添加了一个链接到我的答案。
      • 是的,如果至少它是enum { n = 3; }(一个实常数)会更有意义,但int n = 3 和plain 3 属于同一类型。你可以在 Godbolt 中检查你的 gcc 版本,看看它是否会引发任何警告:godbolt.org/z/YMP6f8
      • 哦,我明白了,是你的 gcc 版本中的一个错误,
      猜你喜欢
      • 2016-01-18
      • 2021-06-25
      • 2014-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-04
      相关资源
      最近更新 更多