文字列定数から「char *」へのC ++非推奨の変換


154

私はクラスを持っています private char str[256];

そしてそれのために私は明示的なコンストラクタを持っています:

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

私はそれを次のように呼びます:

myClass obj("example");

これをコンパイルすると、次の警告が表示されます。

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

なぜこうなった?


1
より安全なコピーのstrncpy(str, func, 255)代わりに使用する必要がありstrcpy(str, func)ます。そして、strncpyが追加しないため、文字列の最後に '\ 0'を追加することを忘れないでください。
Patrice Bernassola、2009年

2
「strncpy(str、func、sizeof(str)); str [sizeof(str)-1] = '\ 0';」と言っても安全です。
ウォーレンヤング

3
上記はあなたが引用した警告を与えるものではないと思いますが、私は非常によく似たコードがそうするだろうと確信しています。意味のある答えを得るには、警告を生成する最小限のコンパイル例を投稿する必要があります。
sbi 2009年

3
@Patrice、Warren:strncpyを使用しないでください。これは、strcpyの安全なバージョンではありません。strcpy_sを使用(または再実装)します。
スティーブジェソップ

問題が発生しました。通常のSolarisまたはARM(ターゲット)ビルドではなく、-X86ビルドでこれらの問題が表示されるだけなので、これは無視します。私のサンプルコードでも通常は警告が表示されないため、まだ修正が見つかりませんでした。皆さん、ありがとうございました!
mkamthan 2009年

回答:


144

これは、次のような状況が発生したときに表示されるエラーメッセージです。

char* pointer_to_nonconst = "string literal";

どうして?まあ、CとC ++は文字列リテラルの型が異なります。Cではタイプはcharの配列で、C ++では定数のchar配列です。いずれの場合も、文字列リテラルの文字を変更することは許可されていないため、C ++のconstは実際には制限ではなく、タイプセーフなものです。安全上の理由から、明示的なキャストなしでは、通常、からconst char*への変換char*はできません。ただし、Cとの下位互換性のために、C ++言語では引き続き文字列リテラルをaに割り当てることchar*ができ、この変換が廃止されることについて警告が表示されます。

したがって、どこかconstでconstの正確さのためにプログラムで1つ以上のが欠落しています。しかし、あなたが私たちに示したコードは、この種の廃止された変換を行わないので問題ではありません。警告は他の場所から来たに違いありません。


17
OPが問題を実際に示すコードを提供しなかったのは、この質問に対する見解と投票を考慮すると残念です。
Shafik Yaghmour 2015年

1
OPのコードで問題を再現するにconstは、MyClassコンストラクターからを削除します。次に、constバックを追加して修正できます。
セオドアマードック

145

警告:

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

あなたがどこか(あなたが投稿したコードではない)で何かをしているので、与えられます:

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

問題は、文字列リテラル(型付きconst char[])をに変換しようとしていることですchar*

配列はポインターに合わせて減衰するので、a const char[]をtoに変換できconst char*ますが、実行しているのは、ミュータブルを定数にすることです。

この変換はおそらくC互換性のために許可されており、言及された警告を与えるだけです。


96

同様に答えていません。2 by fnieto-フェルナンドニエトは、この警告が表示されるのは、コード内のどこか(投稿したコードではない)で発生したためです。

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

ただし、コードを警告なしで保持したい場合は、コードをそれぞれ変更します。

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

つまり、string定数をにキャストするだけ(char *)です。


17
または、関数を作成します
。void

3
@Caproojaはい、この場合、paramを「定数へのポインタ」として宣言することもできます。しかし、この変更により、ユーザーは、実装部分でユーザーが実行している可能性がある「str」ポインタを使用して、アドレスに格納されている値を変更/再割り当てすることができなくなります。ですから、それはあなたが気に留めたいかもしれないものです。
sactiw 2014

1
@sactiw現状を維持する理由void foo(char* str)はありますか?パラメータが非定数として書かれているとしても、私たちはとにかくモディファイできないと思いstrましfooた。
kgf3JfUtW

37

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");

配列は既に定数ポインターであるため、ポインターの代わりに配列を使用することもできます。


7
ソリューション3にはがありstrdupます。コードとは異なり、NUL文字を終了するためのスペースを割り当て、割り当てを超過しません。
Ben Voigt 2014年

2
ソリューション2は避けてください。
オービットのライトネスレース

実際の解決策2は、C ++ではchar * x = static_cast <char *>( "foo bar")です。
Kehe CAI 2016

3
アニルはあなたの答えにコメントを統合しますか?ソリューション3は依然として危険なほど間違っています。
オービットのライトネスレース2016年

@LightnessRacesinOrbit答えを教えてください。ソリューション2と3は避けなければならず、危険なほど間違っていると言う理由がわかりません。
Gladclef、

4

実際、文字列定数リテラルはconst char *でもchar *ではなく、char []です。かなり奇妙ですが、C ++仕様で記述されています。変更すると、コンパイラがコードセグメントに格納する可能性があるため、動作は未定義になります。


5
右辺値としては変更できないため、これはconst char []と言えます。
fnieto-フェルナンドニエト2009年

3

多分これを試すことができます:

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

foo("Hello")

わたしにはできる


2

この問題は、コードの最初のどこかにこのマクロを追加することで解決します。または、それをに追加してください<iostream>

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

8
「または<iostream>に追加しますか?
オービットのライトネスレース

何らかの理由で編集された(それが冗談であることを意味する) "、hehe"がありました
Someguynamedpie

C_TEXT関数呼び出し(foo(C_TEXT("foo"));)には問題ありませんが、値が変数のように格納されている場合、未定義の動作を要求していますchar *x = C_TEXT("foo");- x(割り当て以外の)の使用は、それが指しているメモリが解放されているため、未定義の動作です。
Martin Bonnerがモニカをサポート

1

この問題の理由(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へのconstポインターとして宣言します。つまり、ポイントは現在一定ですが、ポイントされるデータも一定ではありません。ポインターは変更できませんが、ポインターを使用してデータを変更できます。
    1. str++ ;無効です。定数であるポインター変数を変更しようとしています。
    2. *str = 'a';有効。ポイントされているデータを変更しようとしています。私たちの場合、これはコンパイルエラーを引き起こしませんが、文字列がコンパイルされたバイナリの読み取り専用セクションに入る可能性が高いため、ランタイムエラーを引き起こします。このステートメントは、メモリを動的に割り当てた場合に意味があります。char* const str = new char[5];
  3. const char* const str:strをconst charへのconstポインターとして宣言します。この場合、ポインターもポイントされているデータも変更できません。
    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宣言を簡単に理解できる英語のステートメントに、またはその逆に変換できます。これはC唯一のツールであるため、に限定されているもの(constexprなど)をサポートしませんC++


0

私も同じ問題を抱えています。そして、私がやったことは、char *ではなくconst char *を追加することだけです。そして問題は解決しました。他の人が前述したように、これは互換性のあるエラーです。Cは文字列をchar配列として扱い、C ++は文字列をconst char配列として扱います。


0

その価値については、この単純なラッパークラスがC ++文字列の変換に役立つことがわかりましたchar *

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

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

-1

以下は解決策を示しています。文字列をcharの定数配列への変数ポインタに割り当てます(文字列はcharの定数配列への定数ポインタ-長さ情報):

#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';
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.