C/C++: Оптимизация указателей на строковые константы

В вашем событии on_ready вы можете инициализировать отображение идентификаторов серверов в пустые списки:

queues = {}

@bot.event
async def on_ready():
    for server in bot.servers:
        queues[server.id] = []
14
задан Jay Conrod 27 March 2009 в 16:14
поделиться

6 ответов

Это - чрезвычайно легкая оптимизация, вероятно, так так, чтобы большинство разработчиков компилятора даже не считало это большой частью оптимизации вообще. Установка флага оптимизации к самому низкому уровню не означает "Быть абсолютно наивной", в конце концов.

Компиляторы будут варьироваться по тому, насколько агрессивный они в объединяющихся дублирующихся строковых литералах. Они могли бы ограничить себя единственной подпрограммой — помещает те четыре объявления в различные функции вместо единственной функции, и Вы могли бы видеть различные результаты. Другие могли бы сделать всю единицу компиляции. Другие могли бы полагаться на компоновщика, чтобы сделать далее слияние среди нескольких единиц компиляции.

Вы не можете полагаться на это поведение, если в документации Вашего конкретного компилятора не говорится, что Вы можете. Сам язык требует в этом отношении. Я был бы осторожен о доверии ему в моем собственном коде, даже если бы мобильность не была беспокойством, потому что поведение склонно измениться даже между различными версиями компилятора единственного поставщика.

16
ответ дан 1 December 2019 в 05:51
поделиться

На это нельзя полагаться, это - оптимизация, которая не является частью никакого стандарта.

Я изменил соответствующие строки Вашего кода к:

const char* str0 = "Watchmen";
const char* str1 = "atchmen";
char* str2 = "tchmen";
char* str3 = "chmen";

Вывод для-O0 уровня оптимизации:

0x8048830
0x8048839
0x8048841
0x8048848

Но для-O1 это:

0x80487c0
0x80487c1
0x80487c2
0x80487c3

Поскольку Вы видите, что GCC (v4.1.2) снова использовал первую строку во всех последующих подстроках. Это - выбор компилятора, как расположить строковые константы в памяти.

30
ответ дан 1 December 2019 в 05:51
поделиться

Вы не должны рассчитывать на это, конечно. Оптимизатор мог бы сделать что-то хитрое на Вас, и нужно позволить сделать так.

Это однако очень распространено. Я помню назад в '87, одноклассник использовал компилятор C DEC и имел эту странную ошибку, где в весь его литерал 3 превратились 11 (числа, возможно, изменились для защиты невинного). Он даже сделал a printf ("%d\n", 3) и это распечатало 11.

Он позвонил мне, потому что было настолько странно (почему это заставляет людей думать обо мне?), и приблизительно после 30 минут головы, царапающей, мы нашли причину. Это была строка примерно как это:

if (3 = x) break;

Отметьте сингл "=" символ. Да, это было опечаткой. Компилятор имел крошечную ошибку и позволил это. Эффект состоял в том, чтобы повернуть весь его литерал 3 во всей программе во что бы ни случилось, чтобы быть в x в то время.

Так или иначе его ясное компилятор C помещало весь литерал 3 в то же место. Если компилятор C назад в 80-х был способен к выполнению этого, не может быть слишком трудно сделать. Я ожидал бы, что это будет очень распространено.

9
ответ дан 1 December 2019 в 05:51
поделиться

Я не полагался бы на поведение, потому что я сомневаюсь, C или стандарты C++ сделали бы явным это поведение, но это имеет смысл, что компилятор делает это. Это также имеет смысл, что это показывает это поведение даже в отсутствие любой оптимизации, указанной к компилятору; нет никакого компромисса в нем.

Все строковые литералы в C или C++ (например, "строковый литерал") являются только для чтения, и таким образом постоянными. Когда Вы говорите:

char *s = "literal";

Вы - в некотором смысле downcasting строка к типу неконстанты. Тем не менее, Вы не можете покончить с атрибутом "только для чтения" строки: при попытке управлять им, то Вы будете пойманы во времени выполнения, а не во время компиляции. (Который является на самом деле серьезным основанием использовать const char * при присвоении строковых литералов вашей переменной.)

5
ответ дан 1 December 2019 в 05:51
поделиться

Вы, конечно, не должны полагаться на то поведение, но большинство компиляторов сделает это. Любое литеральное значение ("Привет", 42, и т.д.) будет сохранено однажды, и любые указатели на него естественно решат к той единственной ссылке.

Если Вы находите, что должны полагаться на это, то в безопасности и повторно кодируете следующим образом:

char *watchmen = "Watchmen";
char *foo = watchmen;
char *bar = watchmen;
12
ответ дан 1 December 2019 в 05:51
поделиться

Нет, на это нельзя полагаться, но хранение строковых констант только для чтения в пуле является довольно легкой и эффективной оптимизацией. Это - просто вопрос хранения алфавитного списка строк и затем вывода их в объектный файл в конце. Думайте, сколько "\n" или "" констант находится в средней кодовой базе.

Если бы компилятор хотел получить дополнительное воображение, то он мог бы снова использовать суффиксы также: "\n" может быть представлен, указав на последний знак "Hello\n". Но это, вероятно, идет с очень небольшим преимуществом для значительного увеличения сложности.

Так или иначе я не полагаю, что в стандарте говорится что-либо о том, где что-либо хранится действительно. Это будет очень определенной для реализации вещью. Если Вы вставите два из тех объявлений отдельный .cpp файл, то вещи, вероятно, изменятся также (если Ваш компилятор не сделает значительную работу соединения.)

2
ответ дан 1 December 2019 в 05:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: