Прекращение преобразования C++ из строковой константы в 'char*'

У меня есть класс с private char str[256];

и для этого у меня есть явный конструктор:

explicit myClass(const char *func)
{
    strcpy(str,func);
}

Я называю это так:

myClass obj("example");

Когда я компилирую это, я получаю следующее предупреждение:

устаревшее преобразование из строковой константы в 'char*'

Почему это происходит?

11 ответов

Решение

Это сообщение об ошибке вы видите всякий раз, когда у вас возникает такая ситуация:

char* pointer_to_nonconst = "string literal";

Зачем? Ну, C и C++ различаются по типу строкового литерала. В C тип является массивом char, а в C++ - постоянным массивом char. В любом случае, вам не разрешено изменять символы строкового литерала, поэтому const в C++ на самом деле не ограничение, а скорее вопрос безопасности типов. Конверсия из const char* в char* как правило, невозможно без явного приведения из соображений безопасности. Но для обратной совместимости с C язык C++ все еще позволяет присваивать строковый литерал char* и выдает предупреждение об устаревании этого преобразования.

Итак, где бы вы ни пропустили один или несколько constS в вашей программе для правильности const. Но код, который вы показали нам, не является проблемой, так как он не делает такого рода устаревшее преобразование. Предупреждение, должно быть, пришло из другого места.

Предупреждение:

устаревшее преобразование из строковой константы в 'char*'

дается, потому что вы делаете где-то (не в коде, который вы опубликовали) что-то вроде:

void foo(char* str);
foo("hello");

Проблема в том, что вы пытаетесь преобразовать строковый литерал (с типом const char[]) чтобы char*,

Вы можете конвертировать const char[] в const char* потому что массив распадается на указатель, но то, что вы делаете, делает изменяемый константу.

Это преобразование, вероятно, разрешено для совместимости с C и дает вам упомянутое предупреждение.

Как ответа нет. 2 от fnieto - Фернандо Ньето ясно и правильно описывает, что это предупреждение выдается, потому что где-то в вашем коде вы делаете (не в коде, который вы опубликовали) что-то вроде:

void foo(char* str);
foo("hello");

Однако, если вы хотите, чтобы ваш код также не содержал предупреждений, просто внесите соответствующие изменения в свой код:

void foo(char* str);
foo((char *)"hello");

То есть просто брось string постоянный (char *),

Есть 3 решения:

Решение 1:

const char *x = "foo bar";

Решение 2:

char *x = (char *)"foo bar";

Решение 3:

char* x = (char*) malloc(strlen("foo bar")+1); // +1 for the terminator
strcpy(x,"foo bar");

Массивы также можно использовать вместо указателей, поскольку массив уже является постоянным указателем.

Причина этой проблемы (которую даже труднее обнаружить, чем проблема с char* str = "some string" - что другие объяснили) - это когда вы используете constexpr.

constexpr char* str = "some string";

Кажется, что это будет похоже на const char* str, и поэтому не будет вызывать предупреждения, как это было раньше char*, но вместо этого ведет себя как char* const str.

Детали

Постоянный указатель и указатель на константу. Разница междуconst char* str, а также char* const str можно объяснить следующим образом.

  1. const char* str: Объявить str указателем на const char. Это означает, что данные, на которые указывает этот указатель, постоянны. Указатель можно изменить, но любая попытка изменить данные приведет к ошибке компиляции.
    1. str++ ;: ДЕЙСТВИТЕЛЬНО. Мы изменяем указатель, а не данные, на которые указывают.
    2. *str = 'a';: НЕДЕЙСТВИТЕЛЬНО. Мы пытаемся изменить указанные данные.
  2. char* const str: Объявить str константным указателем на char. Это означает, что точка теперь постоянна, но указываемые данные тоже нет. Указатель нельзя изменить, но мы можем изменить данные с помощью указателя.
    1. str++ ;: НЕДЕЙСТВИТЕЛЬНО. Мы пытаемся изменить переменную указателя, которая является константой.
    2. *str = 'a';: ДЕЙСТВИТЕЛЬНО. Мы пытаемся изменить указанные данные. В нашем случае это не вызовет ошибки компиляции, но вызовет ошибку времени выполнения, поскольку строка, скорее всего, перейдет в раздел только для чтения скомпилированного двоичного файла. Это утверждение имело бы смысл, если бы у нас была динамически распределенная память, например.char* const str = new char[5];.
  3. const char* const str: Объявить str как константный указатель на константный символ. В этом случае мы не можем ни изменить указатель, ни данные, на которые указывают.
    1. str++ ;: НЕДЕЙСТВИТЕЛЬНО. Мы пытаемся изменить переменную указателя, которая является константой.
    2. *str = 'a';: НЕДЕЙСТВИТЕЛЬНО. Мы пытаемся изменить данные, на которые указывает этот указатель, который также является постоянным.

В моем случае проблема заключалась в том, что я ожидал constexpr char* str вести себя как const char* str, и нет char* const str, так как визуально кажется ближе к прежнему.

Кроме того, предупреждение, созданное для constexpr char* str = "some string" немного отличается от char* str = "some string".

  1. Предупреждение компилятора для constexpr char* str = "some string": ISO C++11 does not allow conversion from string literal to 'char *const'
  2. Предупреждение компилятора для char* str = "some string": ISO C++11 does not allow conversion from string literal to 'char *'.

Совет

Вы можете использовать конвертер тарабарщины Си ↔ английский для преобразованияCдекларации на легко понятные английские утверждения, и наоборот. ЭтоC только инструмент и, следовательно, не будет поддерживать вещи (например, constexpr), которые являются эксклюзивными для C++.

Может быть, вы можете попробовать это:

void foo(const char* str) 
{
    // Do something
}

foo("Hello")

Меня устраивает

Фактически строковая константа-литерал не является ни const char *, ни char *, а char[]. Это довольно странно, но записано в спецификациях C++; Если вы измените его, поведение не определено, потому что компилятор может сохранить его в сегменте кода.

Я решаю эту проблему, добавив этот макрос в начале кода, где-то. Или добавьте это в <iostream>хе-хе

 #define C_TEXT( text ) ((char*)std::string( text ).c_str())

У меня тоже такая же проблема. Я просто добавил const char* вместо char*. И проблема решена. Как уже упоминалось выше, это совместимая ошибка. C рассматривает строки как массивы символов, а C++ обрабатывает их как массивы const.

Худшая часть этого - типичная неоднозначность в злоупотреблении зарезервированным словом "строка", из-за чего можно ошибочно полагать, что "пример".c_str() решит проблему.

Я считаю, что этот простой класс-обертка полезен для преобразования строк C++ в char *:

class StringWrapper {
    std::vector<char> vec;
public:
    StringWrapper(const std::string &str) : vec(str.begin(), str.end()) {
    }

    char *getChars() {
        return &vec[0];
    }
};

Следующее иллюстрирует решение, назначьте вашу строку указателю переменной на постоянный массив символов char (строка является постоянным указателем на постоянный массив символов char + plus length):

#include <iostream>

void Swap(const char * & left, const char * & right) {
    const char *const temp = left;
    left = right;
    right = temp;
}

int main() {
    const char * x = "Hello"; // These works because you are making a variable
    const char * y = "World"; // pointer to a constant string
    std::cout << "x = " << x << ", y = " << y << '\n';
    Swap(x, y);
    std::cout << "x = " << x << ", y = " << y << '\n';
}
Другие вопросы по тегам