重复文字和硬编码

时间:2010-06-28 10:04:59

标签: c++ c micro-optimization compiler-theory string-interning

我发现以下模式经常发生:

 b->last = ngx_cpymem(b->last, "</pre><hr>", sizeof("</pre><hr>") - 1);

请注意,文字字符串使用了两次。提取物来自nginx源库。

编译器应该能够在编译单元中遇到这些文字时合并这些文字。

我的问题是:

  1. 商业级编译器(VC ++,GCC,LLVM / Clang)在编译单元中遇到这种冗余吗?
  2. 链接目标文件时,(静态)链接器是否会删除此类冗余。
  3. 如果2适用,这种优化会在动态链接期间发生吗?
  4. 如果适用1和2,它们是否适用于所有文字。
  5. 这些问题很重要,因为它允许程序员在不损失效率的情况下进行冗长 - 即,考虑将大量静态数据模型硬连接到程序中(例如,某些低级使用的决策支持系统的规则)级别场景)。

    修改

    2分/澄清

    1. 上面的代码由公认的“主”程序员编写。这家伙一手写了nginx。

    2. 我没有问过文字硬编码的哪种可能机制更好。所以不要偏离主题。

    3. 修改2

      我最初的例子是非常人为的和限制性的。以下代码段显示了嵌入到内部硬编码知识中的字符串文字的用法。第一个片段用于配置解析器告诉它为哪个字符串设置哪个枚举值,第二个片段通常用作程序中的字符串。就个人而言,我很满意,只要编译器使用字符串文字的一个副本,并且由于元素是静态的,它们不会进入全局符号表。

      static ngx_conf_bitmask_t  ngx_http_gzip_proxied_mask[] = {
         { ngx_string("off"), NGX_HTTP_GZIP_PROXIED_OFF },
         { ngx_string("expired"), NGX_HTTP_GZIP_PROXIED_EXPIRED },
         { ngx_string("no-cache"), NGX_HTTP_GZIP_PROXIED_NO_CACHE },
         { ngx_string("no-store"), NGX_HTTP_GZIP_PROXIED_NO_STORE },
         { ngx_string("private"), NGX_HTTP_GZIP_PROXIED_PRIVATE },
         { ngx_string("no_last_modified"), NGX_HTTP_GZIP_PROXIED_NO_LM },
         { ngx_string("no_etag"), NGX_HTTP_GZIP_PROXIED_NO_ETAG },
         { ngx_string("auth"), NGX_HTTP_GZIP_PROXIED_AUTH },
         { ngx_string("any"), NGX_HTTP_GZIP_PROXIED_ANY },
         { ngx_null_string, 0 }
      };
      

      紧随其后:

      static ngx_str_t  ngx_http_gzip_no_cache = ngx_string("no-cache");
      static ngx_str_t  ngx_http_gzip_no_store = ngx_string("no-store");
      static ngx_str_t  ngx_http_gzip_private = ngx_string("private");
      

      对于那些留在话题上的人,勇敢!

5 个答案:

答案 0 :(得分:8)

请注意,对于sizeof("</pre><hr>")的特定情况,几乎可以肯定字符串文字永远不会出现在输出文件中 - 整个sizeof表达式可以在编译时计算为整数常量11 -time。

尽管如此,编译器合并相同的字符串文字仍然是一种非常常见的优化。

答案 1 :(得分:7)

我无法回答你的问题,但在这种情况下总是尝试使用const字符串(甚至#define会更好)。当你重构代码并改变一个文字的值而忘记了另一个时,问题就出现了(在你的例子中不太可能,因为它们彼此相邻,但我之前已经看过了)。

无论编译器能做什么的人工操作,人类仍然可以进行操作:)

答案 2 :(得分:4)

我会很不高兴看到这种模式 - 如果有什么有人更改一个文字而不改变其他?它应该被拉出来;做一个很小的命名常量。

假设你不能出于某种原因,或者只是为了实际回答这个问题:(至少,有趣的。)

我在C中创建了一个类似的程序并用GCC 4.4.3编译它,常量字符串只在生成的可执行文件中出现一次。

编辑:因为它可能是一个简单的测试,这是我用它测试的代码...

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

main(){
    char *n = (char*)malloc(sizeof("teststring"));
    memcpy((void*)n, "teststring", sizeof("teststring"));
    printf("%s\n", n);
}

这是我用来检查字符串出现次数的命令......

strings a.out|grep teststring

但请尽可能考虑使用不易出错的编码实践。

答案 3 :(得分:4)

  1. 对于GCC是的,对其他人也应如此
  2. 对于GNU链接器可能是的(参见-fmerge-constants,-fmerge-all-constants)
  3. 没有
  4. 不确定

答案 4 :(得分:4)

我写了一个小样本代码并编译:

void func (void)
{
    char ps1[128];
    char ps2[128];

    strcpy(ps1, "string_is_the_same");
    strcpy(ps2, "string_is_the_same");

    printf("", ps1, ps2);
}

作为汇编程序文件的结果,即使没有优化,也只有一个文字“string_is_the_same”的实例。但是,不确定是否将这些字符串重复放入不同的文件中 - &gt;不同的目标文件。