4

我看到以下模式经常发生:

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

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

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

我的问题是:

  1. 在编译单元中遇到商业级编译器(VC++、GCC、LLVM/Clang)是否会消除这种冗余?
  2. (静态)链接器在链接目标文件时是否删除了此类冗余。
  3. 如果 2 适用,这种优化会在动态链接期间发生吗?
  4. 如果 1 和 2 适用,它们是否适用于所有文字。

这些问题很重要,因为它允许程序员在不损失效率的情况下变得冗长——例如,考虑将大量静态数据模型硬连接到程序中(例如,在某些低级场景中使用的决策支持系统的规则) .

编辑

2 点/说明

  1. 上面的代码是由公认的“大师”程序员编写的。那家伙单枪匹马写了nginx。

  2. 我没有问过哪种可能的文字硬编码机制更好。因此,不要跑题。

编辑 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");

对于那些留在主题上的人,太棒了!

4

5 回答 5

8

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

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

于 2010-06-28T10:51:14.543 回答
7

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

无论编译器可以做什么优化,人类仍然可以把它搞砸:)

于 2010-06-28T10:09:40.807 回答
6
  1. 对 GCC 是,对其他人也应该如此
  2. 对于 GNU 链接器,也许是的(参见 -fmerge-constants、-fmerge-all-constants)
  3. 没有把握
于 2010-06-28T10:22:08.573 回答
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

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

于 2010-06-28T10:15:29.060 回答
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”的实例。但是,不确定这些字符串是否被重复放置到不同的文件 -> 不同的目标文件中。

于 2010-06-28T10:25:09.363 回答