Почему там различие в выводе, произведенном, когда код компилируется с помощью этих двух компиляторов gcc
и turbo c
.
#include <stdio.h>
int main()
{
char *p = "I am a string";
char *q = "I am a string";
if(p==q)
{
printf("Optimized");
}
else{
printf("Change your compiler");
}
return 0;
}
Я добираюсь "Optimized"
на gcc
и "Change your compiler"
на turbo c
. Почему?
Ваш вопрос был помечен как C, так и C++. Поэтому я бы ответил для обоих языков.
[C]
Из ISO C99 (Раздел 6.4.5/6
)
Не уточняется, являются ли эти массивы различными, если их элементы имеют соответствующие значения.
Это означает, что не определено
, указывают ли p
и q
на один и тот же строковый литерал или нет. В случае gcc
они оба указывают на "I am a string"
(gcc оптимизирует ваш код), тогда как в turbo c
это не так.
Неспецифическое поведение (Unspecified Behavior): Использование неопределенного значения или другое поведение, когда настоящий международный стандарт предоставляет две или более возможности и не предъявляет никаких дополнительных требований к тому, какая из них будет выбрана в каком-либо instance
[C++]
Из ISO C++-98 (Раздел 2.13.4/2
)
Являются ли все строковые литералы различными (то есть, хранятся в непересекающихся объектах), определяется реализацией.
В C++ ваш код вызывает поведение, определяемое реализацией.
Implementation-defined Behavior:
Неспецифическое поведение, где каждая реализация документирует
, как был сделан выбор
Также смотрите этот вопрос.
Поскольку ваш строковый литерал является константным выражением, т.е. вы не должны изменять его через указатель, нет никакого реального смысла хранить его в пространстве памяти дважды. Будучи более новым компилятором, gcc по умолчанию объединяет литералы, в то время как Turbo C этого не делает. Это признак того, что gcc поддерживает более новый стандарт языка, в котором есть понятие const данных.
Turbo C был оптимизирован для быстрой компиляции, поэтому у него нет никаких особенностей, которые могли бы замедлить его работу. Распознавание дубликатов строк было бы замедлением, пусть даже незначительным.
Пожалуйста, забудьте ответы в той же строке, что и
"Это потому, что Turbo C ТАК СОВЕРШЕННО СТАРЫЙ, и они не могли сделать это ТОГДА, потому что это должно было быть БЫСТРО, но GCC совершенно НОВЫЙ и RAD, и поэтому он делает это!".
Оба компилятора поддерживают объединение строковых констант в качестве опции. Опция GCC (-fmerge-constants
) включается на уровнях оптимизации, а опция Turbo C (-d
) по умолчанию выключена. Если вы используете TCC IDE, то зайдите в Options|Compiler...|Code Generation...
и отметьте пункт "Duplicate strings merged
".
На странице руководства gcc:
-fmerge-constants
Попытка объединить идентичные константы (строковые константы и константы с плавающей запятой) через единицы компиляции.
Этот параметр используется по умолчанию для оптимизированной компиляции, если ассемблер и компоновщик поддерживают это. Использовать -fno-merge-constants, чтобы запретить такое поведение.
Включено на уровнях -O, -O2, -O3, -Os.
Отсюда вывод.
Компилятор может хранить две копии одинаковых литералов, если посчитает нужным. Выяснить, так ли это, предположительно и является целью данной программы.
В старые добрые времена ассемблеры хранили все литералы в пуле литералов, и исправление пула литералов было признанной (если не одобренной) техникой изменения "констант" во всей программе.
Если по какой-то случайности компилятор разрешит в этом случае *p = 'H';
то возникнут важные различия в поведении.
Историческая сноска: поскольку адреса были меньше числовых констант с плавающей запятой, FORTRAN использовался для обработки констант с плавающей запятой так же, как C обрабатывает строки. Поскольку память была драгоценна, идентичным константам будет выделяться одно и то же пространство. Кроме того, передача параметров всегда выполнялась по ссылке. Это означало, что если передать числовую константу процедуре, которая изменила свой аргумент, другие вхождения этой «константы» изменили бы значение.
Отсюда старая поговорка: «Переменные - нет, константы - нет».
Между прочим, кто-нибудь заметил ошибку в printf Turbo C 2.0, которая не позволяла использовать формат типа "% 1.1f" для печатать числа вроде 99.99 (выводит 00.0)? Исправлено в версии 2.01, это напоминает мне ошибку калькулятора Windows 3.1.