Пройдя через некоторый код c++ в рамках обзора сертификации PCI DSS, я столкнулся со следующим:
У меня есть метод в некоторой библиотеке, которую мы используем, и одним из ее параметров является char *, скажем, это
void foo(char* arg);
Точка в коде, где он вызывает этот метод, выглядит так:
char mystring[256];
strcpy(mystring, "some value");
....
foo(mystring);
в рамках обзора мы избавляемся от любых strcpy-вызовов (хотя в этом примере это немного тривиально, поскольку "некоторая ценность" явно вписывается в мистификацию)
Таким образом, мы получаем:
char mystring[256];
strncpy(mystring, "some value", sizeof(mystring));
mystring[sizeof(mystring)-1] = '\0';
....
foo(mystring);
Это потому, что я думал
foo("some value")
будет передавать const char *
Однако, к моему удивлению, компилятор (gcc 4) вполне доволен этим. Он даже не дает никаких предупреждений, когда я добавляю -Wall или -Wcast-qual
Мой вопрос заключается в следующем: могу ли я в этом случае безопасно вызвать foo ("некоторое значение"), когда я не знаю, что foo фактически делает (если есть) для его аргумента?
Нет, это небезопасно, если вы не можете гарантировать, что foo не изменит аргумент. Компиляторы могут неявно использовать строковый литерал для char *
для обратной совместимости с кодом C (к сожалению). Вам придется скопировать литерал в модифицируемый буфер символов и передать это вместо этого.
Могу ли я в этом случае безопасно вызывать
foo("some value")
когда я не знаю, чтоfoo
фактически делает (если что-либо) своим аргументом?
Нет. Строковый литерал является постоянным, и попытка его изменения дает неопределенное поведение.
По историческим причинам существует устаревшее преобразование в non-const char*
которое разрешено некоторыми компиляторами, хотя это преобразование больше не действует с С++ 11. Вы не должны полагаться на это, и, надеюсь, вы можете повысить уровень предупреждения на своем компиляторе, чтобы предотвратить его.
Однако, к моему удивлению, компилятор (gcc 4) вполне доволен этим.
Это удивительно. Мой GCC 4.6.3 дает предупреждение по умолчанию; Мне нужно было бы указать -Wno-write-strings
чтобы заставить его замолчать.
Кстати, вы используете strncpy
неправильно. Параметр размера должен быть размером целевого буфера минус единица:
char mystring[256];
strncpy(mystring, "some value", 255);
mystring[255] = '\0';
Цель состоит в том, чтобы избежать переполнения буфера.
sizeof(dest)-1
. Также в C gcc (или, по крайней мере, его ранние версии) не будет рассматривать строковые литералы const
если вы не -Wwrite-strings
ему -Wwrite-strings
предупреждения -Wwrite-strings
. Нет, он не включен в -Wall -Wextra
, вы должны указать его в дополнение к ним. Это предупреждение необходимо считать обязательным на всех платформах, которые размещают строковые литералы на страницах только для чтения (то есть на всех современных).
char*
.