Дублирующиеся литералы и жесткое кодирование - PullRequest
3 голосов
/ 28 июня 2010

Я вижу следующий шаблон, встречающийся довольно часто:

<code> b->last = ngx_cpymem(b->last, "

", sizeof ("
") - 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");

Тем, кто остался по теме, браво!

Ответы [ 5 ]

8 голосов
/ 28 июня 2010

Обратите внимание, что для конкретного случая sizeof("</pre><hr>") практически точно, что строковый литерал никогда не появится в выходном файле - все выражение sizeof может быть оценено как целочисленная константа 11 во время компиляции.

Несмотря на это, для компиляторов по-прежнему очень распространена оптимизация объединения одинаковых строковых литералов.

7 голосов
/ 28 июня 2010

Я не могу ответить на ваши вопросы, но всегда стараюсь использовать константную строку (или даже #define было бы лучше) в таких обстоятельствах.Проблема возникает, когда вы реорганизуете код и изменяете значение одного литерала, забывая другой (это не так вероятно в вашем примере, поскольку они находятся рядом друг с другом, но я видел это раньше).компилятор может делать то, что люди все еще могут это сделать:)

5 голосов
/ 28 июня 2010
  1. Да для GCC, должно быть верно и для других
  2. Возможно, да для компоновщика GNU (см. -Fmerge-constants, -fmerge-all-constants)
  3. Нет
  4. Не уверен
4 голосов
/ 28 июня 2010

Я написал небольшой пример кода и скомпилировал:

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" даже без оптимизации.Однако не уверен, что эти строки не дублируются и помещаются в разные файлы -> разные объектные файлы.

4 голосов
/ 28 июня 2010

Мне было бы очень неприятно видеть этот паттерн - что если кто-то изменит один литерал, не изменив другой?Это должно быть вытащено;сделайте довольно маленькую именованную константу.

Предполагая, что вы не можете по какой-то причине или просто фактически ответить на вопрос: (По крайней мере, анекдотично.)

Я сделал подобную программу на 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

Но, пожалуйста, рассмотрите возможность использования менее подверженных ошибкам методов кодирования, где это возможно.

...