Когда я запускаю эту программу, используя MinGW, я получаю вывод как «=»
#include<iostream>
using namespace std;
int main()
{
char *str1 = "Hello";
char *str2 = "Hello";
if(str1==str2)
cout<<"=";
else
cout<<"!=";return 0;
}
Однако, по логике, это должно быть! =, Потому что это указатели, и они указывают на разные области памяти. Когда я запускаю этот код в моем Turbo C ++, я получаю! =
Вы правы в том, что они указатели. Однако то, указывают ли они на разные местоположения или нет, зависит от реализации. Для компилятора вполне допустимо хранить строковый литерал только один раз и использовать его адрес везде, где он используется в коде.
Нет никаких гарантий, что два указателя указывают на разные области памяти. Может быть, это потому, что оптимизации или компилятор использует свои собственные правила … поведение «Реализация определена».
Согласно стандарту (C ++ 11 §2.14.5 Строковые литералы):
Все ли строковые литералы различны (то есть, сохранены
в неперекрывающихся объектах) определяется реализацией.
Это ожидаемый результат. Вы можете убедиться в этом, посмотрев на базовую сборку. Например, если я строю с:
g++ -S ptr.c
тогда вы можете увидеть следующее в выводе файла (ptr.s):
.file "ptr.c".def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"LC0:
.ascii "Hello\0" ; Note - "Hello" only appears once in
; this data section!
LC1:
.ascii "=\0"LC2:
.ascii "!=\0".text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
[... some stuff deleted for brevity ...]
LCFI5:
call ___main
movl $LC0, -12(%ebp) ; This sets str1
movl $LC0, -8(%ebp) ; This sets str2
movl -12(%ebp), %eax
Я прокомментировал два ключевых бита — только один вид «Hello» находится в разделе rdata основного кода, и вы можете видеть, что str1 и str2 установлены в конце, оба указывают на одну и ту же метку: LC0
, Это потому, что «Hello» является строковым литералом и, что важно, постоянная.
Как уже отмечали другие — это совершенно законно по стандартам.
Тип строкового литерала как "Hello"
является массив Const голец, следовательно, вы направляете два указателя на то, что никогда не может измениться.
Стандарт C ++ дает компиляторам свободу объединять одинаковые постоянные значения (обратите внимание, что компиляторы не требуется сделать так).
Связанный: поэтому объявления являются недействительными и должны быть изменены на:
const char *str1 = "Hello";
const char *str2 = "Hello";
или если вы хотите
char const *str1 = "Hello";
char const *str2 = "Hello";
который хорошо читается при чтении справа налево:
str1 is a pointer to const char
.
char *str1 = "Hello";
— хотя эта строка разрешена (многими компиляторами), на самом деле это плохая идея. Это в основном разрешено только для обратной совместимости с C, а запись в * str1 приводит к неопределенному поведению. Я бы порекомендовал найти параметр компилятора, который выдает предупреждения, когда вы делаете это, и если вашему компилятору не хватает таких предупреждений при поиске нового компилятора.
Стандарт C ++ дает компиляторам и средам исполнения смехотворную свободу в отношении того, где "String literals"
хранятся. Они могли буквально использовать указатель на "literal"
часть "String literals"
в качестве значения указателя для "literal"
и сохранение их в памяти, в которой вы можете избежать ошибки при попытке их редактирования, не является неожиданным.
Обратите внимание, что char buf1[] = "Hello";
делает что-то принципиально другое, чем char* str1 = "Hello";
: фактически инициализирует буфер buf1
с персонажами {'H','e','l','l','o','\0'}
,