GCCで「非推奨の文字列定数から「char *」への変換」警告を取り除く方法は?


409

だから私は非常に大きなコードベースに取り組んでいて、最近この警告をトリガーするgcc 4.3にアップグレードしました:

警告:文字列定数から 'char *'への非推奨の変換

明らかに、これを修正する正しい方法は、次のようなすべての宣言を見つけることです

char *s = "constant string";

または次のような関数呼び出し:

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

そしてそれらをconst charポインタにします。ただし、これは少なくとも564個のファイルを操作することを意味し、現時点で実行したい作業ではありません。現在の問題は、私がで実行している-werrorため、これらの警告を抑制する方法が必要です。どうやってやるの?


554行の置き換えに取り組む場合、sedは良い友達です。ただし、必ず最初にバックアップしてください。
Matt

2
エラーメッセージを抑制する方法と正しい置換の方法についてのディスカッションを確認しました。それについて私は何の意見もありません。しかし、マットは正しい方向に進んでいると思います。何を何に置き換えるかを定義します。正しい正規表現が必要です。コピーに変更を加えます。「diff」を使用して、オリジナルと比較します。sedを使用して変更を行うのは迅速、簡単、無料で、diffも迅速、簡単、無料です。試して、確認する必要がある変更の数を確認してください。何を何に置き換えるかを投稿し、ユーザーに正規表現の置き換えを提案させます。
Thomas Hedden 2017年

全体の議論はこれがgcc警告に従ってまったく修正する必要がある問題である理由の要点を欠いています。その理由は、David Schwartzの回答であるstackoverflow.com/questions/56522654/…にあります。
andig

回答:


227

-Wno-write-stringsgccに渡すと、この警告が抑制されると思います。


6
プラグマを使用して基本的にファイルごとに無効にできますか?
Priyank Bolia 09年

18
@PriyankBolia bdonlanが、Rob Walkerが使用できるという回答にコメントしました#pragma GCC diagnostic ignored "-Wwrite-strings"
MasterMastic 2013年

9
APIを制御する場合を除いて、const char *を受け入れるように署名を変更することに関する@Johnの答えは、より正確です。
jcwenger 2014年

215
これは恐ろしく悪い習慣であり、それらすべての票を獲得したのは残念です。警告はありませんので、無視してください。「おい、あなたは間違っているかもしれない何かをしている、注意してください」という警告があり、「シャットダウン、私は何をしているのかわかっている」のように応答したい場合にのみそれらを抑制すべきです。幼児プログラマの場合はそうではありません。
量子物理学者

9
私は同意します、あなたは警告を取り除くべきではなく、代わりにジョンによって提供された解決策を使うべきです。これは残念ながら受け入れられた答えです。
ジェローム2015

564

文字列リテラルを渡す関数はすべて、の代わりにタイプとして"I am a string literal"使用する必要があります。char const *char*

何かを修正する場合は、正しく修正してください。

説明:

文字列リテラルはタイプなので、文字列リテラルを使用して変更される文字列を初期化することはできませんconst char*。後でそれらを修正するためにconst性を離れてキャストすると、ある未定義の動作、あなたのコピーする必要がありますので、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;
}

25
これは本当ですが、char */を正しく使用しない可能性があるサードパーティのAPIを常に制御できるとは限らないconst char *ため、その場合は通常キャストします。
ideasman42

15
@ppumkin残念ながら、多くのC標準ライブラリの文字列関数char*は、変更されない文字列に対しても引数を取ります。パラメータをaとして受け取り、char const*それを標準関数に渡してaを受け取ると、それが発生しchar*ます。ライブラリ関数が文字列を操作しない場合は、をキャストしてくださいconst
John

常に可能であるとは限らないからといって、多くの場合、この警告が一般的な製品コードに表示されるので、このオプションが推奨されないわけではありません。
LovesTha

1
ソリューションと文字列リテラルの機能を完全に理解しました。しかし、おそらく他の人はそうしないかもしれないので、私は説明の必要性を「保持」します
NicoBerrogorry

1
私はあなたのソリューションを適用する方法を理解していません:(
desmond13

69

私は同様の問題がありました、私はこのようにそれを解決しました:

#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)。


8
@elcuco、あなたは何を提案しますか?私はfooを編集できず、警告の抑制を必要としない解決策を見つけようとしました。私の場合、後者はより運動の問題でしたが、元のポスターではそれが重要に思われました。私の知る限りでは、私の答えは、私の状態とOPの状態の両方を同時に解決する唯一のものなので、誰かにとって貴重な答えになる可能性があります。私の解決策では不十分だと思われる場合は、代替案を提供していただけませんか?(これにはfooの編集や警告の無視は含まれません。)
BlackShift

fooが適切にコード化されていると想定する場合(残念ながら、コード 'Josh Matthews'が話している場合はそうではないようです)、これが最良の解決策です。これは、関数が実際に文字列 'msg'を変更する必要がある場合、定数文字列を渡してコードを破壊するためです。しかし、いずれにしても、エラーは新しいコードではなく古いコードにすでにあるため、これは質問に答えるようには見えません。したがって、とにかく古いコードを変更する必要があります。
ジョアンポルテラ

それも私が取ったアプローチです。そして、誰かがこれを検索している場合char **PyArg_ParseTupleAndKeywords私は次のようにします:static char kw[][16] = {"mode", "name", "ip", "port"}; static char * kwlist[] = {kw[0], kw[1], kw[2], kw[3], NULL};
dashesy

@elcuco:C ++静的配列がどのように機能するかはわかりません。これはポインタだけでなく実際にデータをコピーしますか?
Alexander Malakhov 2013

このアプローチには、場合によっては盲目的に適用するメリットがあるかもしれませんが、IMOは良いというよりは害を及ぼす可能性があります。これを盲目的に適用すると、ポインタがぶら下がってしまう可能性があります。また、無意味な文字列のコピーでコードを膨らませます。
プラグウォッシュ


30

それがアクティブなコードベースである場合でも、コードベースをアップグレードしたい場合があります。もちろん、変更を手動で実行することは現実的ではありませんが、この問題は1つのsedコマンドで一度に解決できると思います。まだ試していないので、以下を塩の粒と一緒に飲んでください。

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

これはすべての場所を見つけることはできませんが(関数呼び出しを考慮していなくても)、問題を軽減し、残りのいくつかの変更を手動で実行できるようにします。


7
宣言だけの警告ではなく機能はとにかくSED FUのための+1を呼び出す解決しないこと:P
ジョアン・ポルテラ

25

コンパイラスイッチを使用できません。だから私はこれを回しました:

char *setf = tigetstr("setf");

これに:

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

1
+1-アプリケーションの左辺値は変更できません。右辺値のみを変更できます。これにより、実際の問題が解決されました。その他は、コンパイラのいくつかの問題を回避するだけです。
elcuco

1
本当に厄介なのは、tigetstr()は(char *)ではなく(const char *)でプロトタイプ化する必要があるということです
vy32

2
これを行うと、代わりに「警告:タイプ 'const char *'からタイプ 'char *'へのキャストが定数をキャストします」が表示されます。すべての警告を取り除くためにconst_castを使用する必要がありました:const_cast <char *>( "setf")
CrouZ

2
私はconstキャストがこのページで最初に受け入れられる解決策だと思います(APIの変更を除く)。
rwst 2015

25

これをファイル内でインライン化する方法は次のとおりなので、Makefileを変更する必要はありません。

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

後でできます...

#pragma GCC diagnostic pop

25

交換する

char *str = "hello";

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

または関数で呼び出す場合:

foo("hello");

これをに置き換えます

foo((char*) "hello");

15

の代わりに:

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

これは機能します:

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

とにかく、定数でない文字列を期待する関数に(定数)文字列を渡すべきではないので、これは正しい方法です。
jfla


7

Test stringconst文字列です。したがって、次のように解決できます。

char str[] = "Test string";

または:

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

4

型キャストを使用しないのはなぜですか?

(char*) "test"

2

定数文字列から文字ポインタへの型キャストを行う、すなわち

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

1

C ++では、以下を置き換えます。

char *str = "hello";

と:

std::string str ("hello");

そしてそれを比較したい場合:

str.compare("HALLO");

1

私はあなたのソリューションを適用する方法を理解していません:( – kalmanIsAGameChanger

Arduino Sketchを使用して、警告を引き起こす機能がありました。

元の関数:char StrContains(char * str、char * sfind)

警告を止めるために、char * strとchar * sfindの前にconstを追加しました。

変更:char StrContains(const char * str、const char * sfind)。

すべての警告が消えました。


これは、「警告:文字列定数から 'char *'への非推奨の変換」と言っていた正しい答えです。
Norbert Boros、2018

0

この状況を見てください:

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 ++ではコンパイルされます。理由はわかりません。


-xで上書きしない限り、gccはファイルをCソースファイルとして扱い、g ++はc ++ソースファイルとして扱います。オプション。したがって、異なる言語であるcとc ++には、警告すべき内容について微妙な違いがあります。
zhaorufei 2017

0

を呼び出して、文字列定数から書き込み可能な文字列を作成することもできますstrdup()

たとえば、次のコードは警告を生成します。

putenv("DEBUG=1");

ただし、次のコードはそうではありません(ヒープに文字列をコピーしてから、に渡しますputenv)。

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

この場合(おそらく他のほとんどの場合)、警告をオフにするのは悪い考えです-理由があるためです。他の代替方法(デフォルトですべての文字列を書き込み可能にする)は、潜在的に非効率的です。

コンパイラがあなたに言っていることを聞いてください!


6
また、その書き込み可能な文字列に割り当てられたメモリもリークします。
RBerteig 2009

1
はい、そうです-それは意図的なものです。上記のように、1回限りのコード(初期化など)では問題ありません。または、自分でメモリを管理し、使い終わったら解放することもできます。
BillAtHRST 2009年

1
の特定のケースputenv()は混乱しています—これは例の良い選択ではありません(少なくとも、putenv()この回答にあるよりも何をするかについての多くの議論がなければ)。それは全く別の議論です。(putenv()POSIXが定義される前のレガシー実装に基づいて、の動作に関するPOSIX仕様に問題があることに注意してください。)IIRC、GNU Cライブラリの最近の(このミレニアム)リリースに、putenv()動作の変更に関連するバグがありました。変更されます。)
ジョナサンレフラー

0

g ++には-wオプションを使用するだけです

例:

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

これは非推奨を回避するのではなく、端末に警告メッセージを表示しないようにすることを覚えておいてください。

廃止を本当に避けたい場合は、次のようにconstキーワードを使用します。

const char* s="constant string";  


0

現在の問題は、私が-Werrorで実行していることです

これがあなたの本当の問題です、IMO。(char *)から(const char *)に移動するいくつかの自動化された方法を試すことができますが、私はそれらにお金をかけるだけでうまくいきません。少なくとも一部の作業には人間を関与させる必要があります。短期的には、警告を無視して(ただし、IMOはオンのままにしておくか、修正されません)、-Werrorを削除します。


9
人々が-Werrorを使用する理由は、警告が修正されるようにするためです。それ以外の場合は修正されません。
Zan Lynx 2010年

2
人々が-Werrorを使用する理由は、彼らがおもちゃのプロジェクトだけに取り組んだか、マゾヒスティックだからです。10万以上のLOCがある場合、GCCの更新が原因でコードのビルドが失敗するのは現実的な問題です。ディト。"-Wno-write-strings"のようなジャンクをビルドに追加して、迷惑な警告を取り除きます(この投稿で最高評価のコメントが示唆するように)。
James Antill、2010年


3
@ジェームズ:あなたは興味深い点を指摘しますが、もっと良い方法があるはずです。警告をすぐに修正しないのは無意味のようです。古い警告のすべてを削除していないのに、新しいコードが新しい警告を呼び出したときにどのように認識しますか?私の経験では、それは人々が彼らが無視してはならないという警告を無視することにつながります。
nobar '29 / 07/29

2
@ジェームズ:私たちのおもちゃプロジェクトは1.5 + M LOC(多言語)です。nobarが言ったように、-Werrorは、あり得ないはずの警告を無視することを避け、コンパイラの新しいバージョンが上がるたびに、すべてを再チェックする必要があります。-Wno-write-stringsは、ファイルごとにPythonラッパーにBoostを使用するときに使用されます。これは、Boostを書き換えないためです(現在、2017では、Boostを使用せず、C ++ 11 / cython)。無視された各警告は、品質チェックで定期的に確認して、コードで回避できるか、それともまだ不可能かを確認する必要があります。
msn 2017

0

助けてくれてありがとう。あちこちから選ぶと、この解決策が出てきます。これはクリーンにコンパイルされます。まだコードをテストしていません。明日...多分...

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つのアイテムしかない。しかし、もっとあるかもしれません。残りは今のところメモリを節約するためにコメントアウトされています。


-1
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、文字列、デフォルトでアクティブになって

これが、異なる振る舞いがある理由です。のマクロを使用すると、Boost_pythonこのような警告が生成されます。したがって-Wno-write-strings、常に使用するため、C ++のコンパイル時に使用します。-Werror


-1

文字列をaとして宣言constすると問題が解決します:

char const*s = "constant string";
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.