Как избавиться от предупреждений "устаревшее преобразование строковой константы в" char * "в GCC?

Итак, я работаю над чрезвычайно большой базой кода и недавно обновился до gcc 4.3, который теперь вызывает это предупреждение:

warning: deprecated conversion from string constant to ‘char*’

Очевидно, что правильный способ исправить это - найти каждое объявление вроде

char *s = "constant string";

или вызов функции, например:

void foo(char *s);
foo("constant string");

и сделайте из них указатели const char. Однако это означало бы прикоснуться как минимум к 564 файлам, что не является задачей, которую я хочу выполнять в данный момент. Сейчас проблема в том, что я работаю с -werror, поэтому мне нужен способ подавить эти предупреждения. Как я могу это сделать?

Когда вы решите заменить 554 строки, sed - ваш хороший друг. Однако сначала убедитесь, что вы сделали резервную копию.

Matt 30.09.2015 03:21

Я просмотрел дискуссии о том, как подавлять сообщения об ошибках и какие должны быть правильные замены. У меня нет никаких мнений по этому поводу. Однако я думаю, что Мэтт на правильном пути. Определите, что вы хотите заменить чем. Вам просто нужно правильное регулярное выражение (я). Внесите изменения в копию. Используйте "diff", чтобы сравнить их с оригиналом. Внесение изменений с помощью sed выполняется быстро, легко и бесплатно, а diff также выполняется быстро, легко и бесплатно. Попробуйте и посмотрите, сколько изменений вам нужно просмотреть. Опубликуйте то, что вы хотите заменить, и позвольте пользователям предлагать замены регулярным выражениям.

Thomas Hedden 23.01.2017 05:27

Во всем обсуждении отсутствует точка Почему, это проблема, которая вообще требует исправления в соответствии с предупреждением gcc. Причина в ответе Дэвида Шварца stackoverflow.com/questions/56522654/….

andig 26.05.2020 17:59
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
417
3
432 036
23
Перейти к ответу Данный вопрос помечен как решенный

Ответы 23

Ответ принят как подходящий

Я считаю, что передача -Wno-write-strings в gcc подавит это предупреждение.

Можно ли отключить его для каждого файла с помощью прагм.

Priyank Bolia 21.06.2009 19:50

@PriyankBolia bdonlan прокомментировал ответ Роба Уокера, что он может использовать #pragma GCC diagnostic ignored "-Wwrite-strings".

MasterMastic 19.01.2013 01:05

За исключением случаев, когда вы управляете API, и в этом случае ответ @ John ниже об изменении подписи для принятия const char * является более правильным.

jcwenger 27.06.2014 19:07

ЭТО УЖАСНО ПЛОХАЯ ПРАКТИКА, и мне жаль, что она получила все эти голоса. Предупреждений нет, поэтому вы их игнорируете. Предупреждения говорят вам: «чувак, ты делаешь что-то, что может быть неправильно, будь осторожен», и тебе следует подавлять их только тогда, когда ты хочешь ответить типа «заткнись, я знаю, что делаю», что, скорее всего, не в случае с младенческими программистами.

The Quantum Physicist 07.04.2015 12:43

Я согласен, вам не следует избавляться от предупреждения и вместо этого использовать решение, предоставленное Джоном. Жаль, что это принятый ответ!

Jérôme 31.08.2015 16:42

это, очевидно, нужно делать на этапе компиляции, а не на заключительном этапе связывания.

DragonLord 05.12.2015 06:12

Если вы хотите сохранить предупреждения, но не рассматривать их как ошибки, вы можете сделать "-Wno-error = write-strings".

plugwash 19.08.2016 14:25

Почему не лучший ответ "Don't pass -werror"? Это решает не только эту проблему, но и следующую.

David Schwartz 30.01.2017 21:28

Проблема с предупреждениями заключается в том, что действительно важные предупреждения слишком легко потеряться в море мелких предупреждений, отчетов о ходе создания и т. д. В то время как ошибки привлекают немедленное внимание, потому что они вызывают сбой сборки. IMO во время разработки лучше сделать отдельные предупреждения нефатальными с помощью "-Wno-error =", чем полностью избавиться от Werror.

plugwash 19.05.2017 18:49

Отключение важных предупреждений - это действительно плохо. Согласовано. Тем не менее, чем это предупреждение вообще полезно? Я не могу понять, как «исправление» этого предупреждения улучшит код и никоим образом не уменьшит ошибочное поведение. Я здесь не прав?

Frederick Ollinger 23.07.2018 20:55

@FrederickOllinger, вы наверняка получили это с тех пор, но просто чтобы ответить на комментарий, он делает код более безопасным и правильным, потому что, когда функция принимает char* и пытается его изменить, если вы вызываете функцию со строковым литералом - который не доступен для записи - вы получите ошибку сегментации.

renardesque 27.12.2018 15:52

Ознакомьтесь с поддержкой gcc Диагностическая прагма и списком -W параметры предупреждений (изменено: новая ссылка на параметры предупреждений).

Для gcc вы можете использовать директивы #pragma warning, как описано в здесь.

Это действительно так: #pragma GCC диагностика игнорирует "-Wwrite-strings"

bdonlan 06.05.2009 00:56

Этот ответ на самом деле не содержит ответа.

Asteroids With Wings 23.12.2020 02:16

Если это активная база кода, вы все равно можете обновить ее. Конечно, внести изменения вручную невозможно, но я считаю, что эту проблему можно решить раз и навсегда с помощью одной-единственной команды sed. Однако я не пробовал, так что отнеситесь к следующему с недоверием.

find . -exec sed -E -i .backup -n \
    -e 's/char\s*\*\s*(\w+)\s*= "/char const*  = "/g' {} \;

Это может не найти всех мест (даже без учета вызовов функций), но это уменьшит проблему и позволит выполнить несколько оставшихся изменений вручную.

который в любом случае решает только предупреждения объявлений, а не вызовы функций +1 для sed fu: p

João Portela 03.11.2009 22:46

The problem right now is that I'm running with -Werror

Это твоя настоящая проблема, ИМО. Вы можете попробовать несколько автоматизированных способов перехода от (char *) к (const char *), но я бы положил деньги на то, чтобы они не просто работали. По крайней мере, для некоторых работ вам нужно будет привлечь человека. На короткое время просто игнорируйте предупреждение (но IMO оставьте его включенным, иначе оно никогда не будет исправлено) и просто удалите -Werror.

Причина, по которой люди используют -Werror, заключается в том, что предупреждения делать исправляются. В противном случае они никогда не исправятся.

Zan Lynx 23.06.2010 03:18

Люди используют -Werror потому, что они работали только над игрушечными проектами, или они мазохисты. Если ваш код не может быть собран из-за обновления GCC, это настоящая проблема, когда у вас 100k + LOC. Дито. кто-то добавляет в сборку мусор, например "-Wno-write-strings", чтобы избавиться от надоедливых предупреждений (как предполагает самый высокий рейтинг в этом сообщении).

James Antill 24.06.2010 00:22

в этой теме есть явные разногласия, например программист.97things.oreilly.com/wiki/index.php/…

João Portela 24.11.2010 02:00

@ Джеймс: Вы подметили интересный момент, но должен быть способ получше. Кажется бессмысленным не устранять предупреждения немедленно - как узнать, когда новый код вызвал новое предупреждение, если вы не удалили все старые предупреждения? По моему опыту, это просто приводит к тому, что люди игнорируют предупреждения, которые им не следует игнорировать.

Brent Bradburn 30.07.2011 02:44

@James: наш игрушечный проект - 1,5+ M LOC (многоязычный). Как сказал nobar, -Werror позволяет избежать игнорирования предупреждений, которых не должно быть, и да, каждый раз, когда возникает новая версия компилятора, мы должны перепроверять все. -Wno-write-strings просто используется при использовании Boost для оболочек Python в файловом режиме, потому что мы не собираемся переписывать Boost (и сейчас, 2017, мы предпочитаем не использовать Boost, а C++ 11 / cython). Каждое проигнорированное предупреждение должно затем периодически проверяться проверкой качества, чтобы увидеть, можно ли теперь избежать с помощью кода или пока это невозможно.

msn 17.02.2017 14:34

-Werror был разницей между угрозой отказа одного из наших клиентов отменить крупный контракт и временем безотказной работы пять девяток. Некоторые сообщения были бессмысленными стилистическими проблемами; многие ожидали ошибки.

Andrew Lazarus 19.01.2019 02:09

Почему вы не используете опцию -Wno-deprecated, чтобы игнорировать устаревшие предупреждающие сообщения?

У меня была аналогичная проблема, решил я вот так:

#include <string.h>

extern void foo(char* m);

int main() {
    // warning: deprecated conversion from string constant to ‘char*’
    //foo("Hello");

    // no more warning
    char msg[] = "Hello";
    foo(msg);
}

Это подходящий способ решить эту проблему? У меня нет доступа к foo, чтобы адаптировать его к const char*, хотя это было бы лучшим решением (потому что foo не меняет m).

@elcuco, что бы вы предложили? Я не мог редактировать foo и пытался найти решение, которое не требовало подавления предупреждения. В моем случае последнее было скорее упражнением, но для оригинального плаката это казалось важным. Насколько я могу судить, мой ответ - единственный, который решал бы как мои условия, так и условия OP одновременно, так что это мог бы быть ценный ответ для кого-то. Если вы считаете, что мое решение недостаточно хорошее, не могли бы вы предоставить альтернативу? (Это не включает редактирование foo или игнорирование предупреждения.)

BlackShift 28.09.2009 20:45

если мы предположим, что foo правильно закодирован (что, к сожалению, не похоже на код, о котором говорит Джош Мэтьюз), это лучшее решение. это потому, что если функции действительно нужно изменить строку 'msg', передавая ей постоянную строку, код нарушится, верно? но в любом случае это, похоже, не отвечает на вопрос, потому что ошибки уже есть в старом коде, а не в новом, поэтому ему все равно придется изменить старый код.

João Portela 03.11.2009 22:43

Я тоже придерживался этого подхода. И если кто-то ищет здесь случаи char ** в PyArg_ParseTupleAndKeywords, я делаю что-то вроде этого: static char kw[][16] = {"mode", "name", "ip", "port"}; static char * kwlist[] = {kw[0], kw[1], kw[2], kw[3], NULL};

dashesy 16.05.2012 08:56

@elcuco: я не уверен, как работают статические массивы C++. Будет ли это копировать действительно какие-то данные, а не только указатель?

Alexander Malakhov 11.02.2013 13:41

Хотя этот подход может иметь свои достоинства, в некоторых случаях применение его вслепую, ИМО, скорее всего, принесет больше вреда, чем пользы. Применение этого вслепую может легко привести к зависанию указателей. Это также приведет к раздуванию кода бессмысленными копиями строк.

plugwash 19.05.2017 18:30

Вы также можете создать доступную для записи строку из строковой константы, вызвав strdup().

Например, этот код генерирует предупреждение:

putenv("DEBUG=1");

Однако следующий код этого не делает (он делает копию строки в куче перед передачей ее putenv):

putenv(strdup("DEBUG=1"));

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

Послушайте, что вам говорит компилятор!

И это также приводит к утечке памяти, выделенной для этой записываемой строки.

RBerteig 06.05.2009 00:55

Да, это так - это специально. Не проблема с одноразовым (например, инициализационным) кодом, как указано выше. Или вы можете управлять памятью самостоятельно и высвободить ее, когда закончите с ней.

BillAtHRST 20.06.2009 23:17

Частный случай putenv() чреват - это не лучший выбор (по крайней мере, не без гораздо большего обсуждения того, что делает putenv(), чем в этом ответе). Это отдельное обсуждение. (Обратите внимание, что спецификация POSIX для поведения putenv() проблематична из-за устаревших реализаций до того, как был определен POSIX.) IIRC, в недавнем (в этом тысячелетии) выпуске библиотеки GNU C была ошибка, связанная с поведением putenv(). меняется и возвращается обратно.)

Jonathan Leffler 29.06.2017 22:54

Я не могу использовать переключатель компилятора. Итак, я повернул это:

char *setf = tigetstr("setf");

к этому:

char *setf = tigetstr((char *)"setf");

+1 - вы не можете изменить lvalue приложений, только rvalue. это помогло решить настоящую проблему. другие просто помогают обойти некоторые проблемы с компилятором.

elcuco 22.09.2009 18:50

Что действительно раздражает, так это то, что tigetstr () должен быть прототипирован с помощью (const char *), а не (char *)

vy32 23.09.2009 10:24

Когда я делаю это, я получаю «предупреждение: приведение типа« const char * »к типу« char * »вместо этого отбрасывает константу». Мне пришлось использовать const_cast, чтобы избавиться от всех предупреждений: const_cast <char *> ("setf")

CrouZ 05.03.2015 12:58

Я думаю, что константное приведение - первое приемлемое решение на этой странице (за исключением изменения API).

rwst 14.04.2015 18:45

Test string - это константная строка. Итак, вы можете решить так:

char str[] = "Test string";

или же:

const char* str = "Test string";
printf(str);

см. эту ситуацию:

typedef struct tagPyTypeObject
{
    PyObject_HEAD;
    char *name;
    PrintFun print;
    AddFun add;
    HashFun hash;
} PyTypeObject;

PyTypeObject PyDict_Type=
{
    PyObject_HEAD_INIT(&PyType_Type),
    "dict",
    dict_print,
    0,
    0
};

следите за полем имени, в gcc он компилируется без предупреждения, но в g ++ это будет, я не знаю почему.

gcc подразумевает обработку файла как исходный файл C, g ++ рассматривает его как исходный файл C++, если не переопределить с помощью -x ?? вариант. Итак, разные языки, c и C++, имеют тонкие различия в том, о чем следует предупреждать.

zhaorufei 24.07.2017 22:27

Почему бы просто не использовать приведение типов?

(char*) "test"

Вот как это сделать в файле, так что вам не нужно изменять свой Makefile.

// gets rid of annoying "deprecated conversion from string constant blah blah" warning
#pragma GCC diagnostic ignored "-Wwrite-strings"

Вы можете позже ...

#pragma GCC diagnostic pop

PyTypeObject PyDict_Type=
{ ...

PyTypeObject PyDict_Type=
{
  PyObject_HEAD_INIT(&PyType_Type),
                     "dict",
                     dict_print,
                     0,
                     0
}; 

следите за полем имени, в gcc он компилируется без предупреждения, но в g ++ это будет, я не знаю почему.

в gcc (Compiling C) по умолчанию активна -Wno-write-strings.

в g++ (Compiling C++) -Wwrite-strings активна по умолчанию

Вот почему есть другое поведение. У нас использование макросов Boost_python генерирует такие предупреждения. Итак, мы используем -Wno-write-strings при компиляции C++, так как мы всегда используем -Werror.

просто используйте параметр -w для g ++

пример:

g ++ -w -o simple.o simple.cpp -lpthread

Помните, что это не предотвращает устаревание, а предотвращает отображение предупреждающего сообщения на терминале.

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

const char* s = "constant string";  

Любые функции, в которые вы передаете строковые литералы "I am a string literal", должны использовать char const * в качестве типа вместо char*.

Если собираетесь что-то исправить, исправляйте правильно.

Объяснение:

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

Пример:

#include <iostream>

void print(char* ch);

void print(const char* ch) {
    std::cout<<ch;
}

int main() {
    print("Hello");
    return 0;
}

Хотя это правда, у вас не всегда есть контроль над сторонними API, которые могут неправильно использовать char * / const char *, поэтому в этом случае я обычно использую.

ideasman42 02.04.2014 08:15

@ppumkin К сожалению, многие строковые функции стандартной библиотеки C принимают аргументы как char* даже для строк, которые не будут изменены. Если вы возьмете параметр как char const* и передадите его стандартной функции, принимающей char*, вы попадете в это. Если библиотечная функция не будет управлять строкой, вы можете отказаться от const.

John 08.06.2015 06:10

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

LovesTha 24.05.2017 02:31

Даже если я чувствую, что это правильный ответ, я считаю, что ему не хватает надлежащего объяснения. Не могли бы вы отредактировать и добавить объяснение? Это не требует подробностей. Может, пару слов и ссылку?

NicoBerrogorry 06.12.2017 21:17

Теперь я полностью понимаю решение и функциональность строковых литералов. Но, возможно, другие этого не делают, поэтому я "придерживаюсь" необходимости объяснения.

NicoBerrogorry 06.12.2017 21:28

Я не понимаю, как применить ваше решение :(

desmond13 08.03.2018 18:53

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

HaseeB Mir 25.05.2018 21:03

Выполните приведение типов из постоянной строки в указатель char, т.е.

char *s = (char *) "constant string";

Вместо:

void foo(char *s);
foo("constant string");

Это работает:

void foo(const char s[]);
foo("constant string");

Это правильный способ сделать это, поскольку вы не должны передавать (константную) строку функции, которая в любом случае ожидает непостоянную строку!

jfla 12.12.2014 20:18

В C++ используйте const_cast, как показано ниже.

char* str = const_cast<char*>("Test string");

Заменять

char *str = "hello";

с

char *str = (char*)"hello";

или если вы вызываете функцию:

foo("hello");

замените это на

foo((char*) "hello");

Спасибо всем за помощь. Выбор здесь и там приходит это решение. Это компилируется чисто. Код еще не тестировал. Может быть, завтра...

const char * timeServer[] = { "pool.ntp.org" }; // 0 - Worldwide 
#define WHICH_NTP            0 // Which NTP server name to use.
...
sendNTPpacket(const_cast<char*>(timeServer[WHICH_NTP])); // send an NTP packet to a server
...
void sendNTPpacket(char* address) { code }

Я знаю, что в массиве timeServer всего 1 элемент. Но могло быть и больше. Остальные пока закомментированы для экономии памяти.

В C++ замените:

char *str = "hello";

с:

std::string str ("hello");

И если хотите сравнить:

str.compare("HALLO");

I don't understand how to apply your solution :( – kalmanIsAGameChanger

Работая с Arduino Sketch, у меня была функция, вызывающая мои предупреждения.

Original function: char StrContains(char *str, char *sfind)

Чтобы отключить предупреждения, я добавил const перед char * str и char * sfind.

Modified: char StrContains(const char *str, const char *sfind).

Все предупреждения исчезли.

Это правильный ответ, согласно предупреждению: «предупреждение: устаревшее преобразование строковой константы в« char * »».

Norbert Boros 22.07.2018 08:20

Передавая string constants функциям, напишите его как:

void setpart(const char name[]);

setpart("Hello");

вместо const char name[] можно также написать const char \*name

Мне удалось удалить эту ошибку:

[Warning] deprecated conversion from string constant to 'char*' [-Wwrite-strings]

Другие вопросы по теме