3

я вижу, картина последующих происходит довольно часто:Повторяющиеся литералы и жесткое кодирование

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. Я не спрашивал, какой из возможных механизмов буквального жесткого кодирования лучше. Поэтому не уходите из темы.

Edit 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"); 

до тех, которые остались на тему, браво!

+2

Извините, но вы беспокоитесь, что высокооктановое топливо заставит машину двигаться быстрее, но не учитывая, что дорога заполнена отверстиями в горшках. Выберите лучшую дорогу, поставив свои литералы в константы. (ОК не лучшая метафора когда-либо, но она работает на точку) –

+4

Почему вы ** хотите ** повторить себя в своем коде? Гораздо лучший вопрос: «Можно ли ** избегать ** быть многословным, не теряя эффективности?» – jalf

+2

Хотя мне придется согласиться с jalf (программистом «master» или нет), ответ на ваш вопрос «да», все достойные компиляторы будут не только объединять дублированные строковые литералы в одной и той же единицы перевода, но и компоновщик также объединит дубликаты через единицы перевода. Это справедливо даже для датированных компиляторов, таких как CW 8, которые предоставляют это как вариант компоновщика. Конечно, этого не произойдет, конечно, в разделяемых библиотеках/библиотеках DLL. Однако, если ваш код зависит от дублированных строковых литералов, чтобы разделить один и тот же адрес, тогда код будет катастрофой в ожидании. – stinky472

ответ

8

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

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

+1

Как насчет линкеров? – pmod

+1

@Pmod: Я так не верю, но я еще не играл с новой функцией оптимизации ссылок в GCC. – caf

+2

Выражение 'sizeof' - это константа времени компиляции (по стандарту C++). Поэтому «практически определенные» кажутся преуменьшенными. – MSalters

8

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

Независимо optomisations компилятор может сделать человек еще может трахнуть его :)

+0

+ газильон, если бы мог. –

+2

Эта последняя строка миллион раз, а остальная часть тоже!Резервирование кричит «вставить ошибку здесь». –

+1

-1 для не по теме. это не программирование 101. –

5

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

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

Я сделал подобную программу в C и скомпилирован с GCC 4.4.3, постоянная строка появилась только один раз в результирующем исполняемом файле.

Edit: Так как это может быть полезно в качестве простого теста, вот код, который я тестировал с ...

#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 

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

+0

компилятор делает эту оптимизацию для вас. +1 для командной строки для проверки – INS

4
  1. Да для GCC, должно быть верно и для других
  2. Может быть, да, для GNU линкер (см -fmerge-константы, -fmerge-все-константы)
  3. Нет
  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» даже без оптимизации. Однако, не уверен, что эти строки не дублируются, помещаются в разные файлы -> разные объектные файлы.

+0

О, было немного поздно .. – pmod

+0

хороший ответ в любом случае: D –

Смежные вопросы