ページ 1 / 1
E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
Posted: 2018年3月09日(金) 03:31
by hands
独習C++の練習問題
図書館の図書目録の項目を管理するための、cardという名前のクラスを作成しなさい。このクラスに本のタイトル、著者、在庫冊数を格納します。タイトルと著者を文字列として保存し、在庫冊数を整数として保存します。store()という名前の公開メンバ関数を使用して本の情報を保存し、show()という名前の公開メンバ関数を使用して情報を表示します。このクラスの動作を確認するために、単純なmain()関数を追加しなさい。
に対しての解答、(以下のコード)をVisual Studio Community 2017で実行したところ
エラー (アクティブ) E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
が発生します。
これを回避するためにはどこを修正すれば良いのでしょうか。
型のパラメーターと互換性がないとはどういうことでしょうか。
コード:
#include <iostream>
#include <cstring>
using namespace std;
class card {
char title[80];
char author[40];
int number;
public:
void store(char *t, char *name, int num);
void show();
};
void card::store(char *t, char *name, int num)
{
strcpy(title, t);
strcpy(author, name);
number = num;
}
void card::show()
{
cout << "本のタイトル: " << title << "\n";
cout << "著者: " << author << "\n";
cout << "冊数: " << number << "\n";
}
int main()
{
card book1, book2, book3;
book1.store("Dune", "Frank Herbert", 2);
book2.store("The Foundation Trilogy", "Isaac Asimov", 2);
book3.store("The Rainbow", "D.H.Lawrence", 1);
book1.show();
book2.show();
book3.show();
return 0;
}
Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
Posted: 2018年3月09日(金) 10:13
by Bull
オフトピック
以前どこかで似たような回答をした記憶があるんだけど...
何でこのエラーが出るのかちょっと不思議
まずエラーになる理由ですが、C++ では文字列リテラルの型は const char [] です。これを関数の実引数に使うと const char * に変換されます。一方 void store(char *t, char *name, int num); で、関数の仮引数は const 無しですので、互換性がないと言うことです。
文字列リテラルは変更不可なのに store() 内部で文字列を変更されてしまう可能性があるので、エラーにしているのでしょう。
ただ、これは歴史的経緯で許容されているはずです。VC++ でもデフォルトではエラーにならないはずですが、/Zc:strictStrings オプションを指定するとこのようなエラーになります。Visual Studioで普通にプロジェクトを作成するとこのオプションを指定されていないと思いますが、プロパティを変更していますか?
/Zc:strictStrings オプションを指定しなければエラーにならないと思います。
また、store() の仮引数に const を付けて
コード:
void store(const char *t, const char *name, int num);
にしてもいいと思います。
Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
Posted: 2018年3月09日(金) 10:34
by tk-xleader
Bull さんが書きました:
ただ、これは歴史的経緯で許容されているはずです。
C++11以降は、文字列リテラルをchar*に暗黙変換できるという仕様は削除されました。
Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
Posted: 2018年3月09日(金) 15:15
by Bull
tk-xleader さんが書きました: ↑7年前
Bull さんが書きました:
ただ、これは歴史的経緯で許容されているはずです。
C++11以降は、文字列リテラルをchar*に暗黙変換できるという仕様は削除されました。
あっ、そうなんですね。
C++98でもそうしたかったらしいのですが、そうできなかったという話を聞いたことがあります。
文字列リテラルは const char * で受けるのが正当なのでしょうが、それを厳密にやってしまうと、過去のソースの修正が大変なことになりそうです。そういうこともあって、多くのコンパイラーではまだ const 無しで受けることを許容しているのでしょうね。
もちろん今後作成するソースは const を付けるべきですが。
Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
Posted: 2018年3月09日(金) 21:39
by hands
Bullさん、tk-xleaderさんありがとうございます。
私もBullさんのおっしゃるように、constが付いてないからなのかな?とは思い至りました。
そこでご指摘の通りconstを付けてみました。
コード:
void store(const char *t, const char *name, int num);
オフトピック
すみません。~さんが書きました
の書き方がわかりません。
すると、
コード:
void card::store(char *t, char *name, int num)
…の方も互換性がないよという風なことを言われたので
コード:
void card::store(const char *t, const char *name, int num)
同じく修正しました…が、
エラー C4996 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.が発生します。
2つ目のコードの修正の仕方が間違っていたでしょうか?
ちなみにですが、BULLさんがおっしゃる/Zc:strictStrings オプションというのは、初めて聞きました。
ですので、いじったことはないかと思うのですが、そのつもりがなくとも、変更されてしまう類のものでしょうか。
よろしければこちらの確認の方法も併せてご教授願えれば幸いです。
Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
Posted: 2018年3月09日(金) 23:11
by Bull
コード:
char title[80];
char author[40];
タイトルと作者は固定長で定義されていますが、これに 80/40 文字以上をコピーしたらどうなるでしょう?
そんなことしたら駄目ですよね。strcpy() ではそういうチェックは出来ませんから、strcpy_s() を使ってくださいと言うことなんだけど、そこは本質的なとこじゃないから、とりあえずエラー無しでコンパイルするためには、プログラムの先頭に
コード:
#define _CRT_SECURE_NO_WARNINGS
を追加してください。
オフトピック
C++なら std::string を使いましょうという話になりそうですが、それはまあ置いておいて
プロジェクトのプロパティで[C/C++]→[すべてのオプション]→[その他のオプション]に /Zc:strictString が指定されていると思われますが、前に書いたように、このオプションはデフォルトでは指定されないはずなので、指定されてなかったら私にはちょっとわかりません。
Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
Posted: 2018年3月10日(土) 00:22
by hands
ありがとうございます。
Bullさんのおかげで、ようやく先に進めます。
コード:
#define _CRT_SECURE_NO_WARNINGS
を使うやり方と
コード:
strcpy_s(title, t);
strcpy_s(author, name);
number = num;
どちらもうまく行きました。
率直に申しあげますと、stringを使った方法が気になっております。
Bull さんが書きました: ↑7年前
オフトピック
C++なら std::string を使いましょうという話になりそうですが、それはまあ置いておいて
プロジェクトのプロパティで[C/C++]→[すべてのオプション]→[その他のオプション]に /Zc:strictString が指定されていると思われますが、前に書いたように、このオプションはデフォルトでは指定されないはずなので、指定されてなかったら私にはちょっとわかりません。
もしよろしければ、どなたかお時間のある時にコメント頂ける方いらっしゃいましたら教えてください。
尚、[その他のオプション]は空欄でした。
Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
Posted: 2018年3月12日(月) 02:47
by かずま
hands さんが書きました: ↑7年前
コード:
strcpy_s(title, t);
strcpy_s(author, name);
number = num;
どちらもうまく行きました。
本当にうまく行きましたか?
strcpy_s は引数が 3個必要です。
https://msdn.microsoft.com/ja-jp/library/td1esda9.aspx
Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
Posted: 2018年3月12日(月) 02:58
by かずま
string を使って書くと、
コード:
#include <iostream>
#include <string> // <-- <cstring>
using namespace std;
class card {
string title; // <-- char title[80];
string author; // <-- char author[40];
int number;
public:
void store(const string& t, const string& name, int num); // string
void show();
};
void card::store(const string& t, const string& name, int num) // string
{
title = t; // <-- strcpy(title, t);
author= name; // <-- strcpy(author, name);
number = num;
}
void card::show()
{
cout << "本のタイトル: " << title << "\n";
cout << "著者: " << author << "\n";
cout << "冊数: " << number << "\n";
}
int main()
{
card book1, book2, book3;
book1.store("Dune", "Frank Herbert", 2);
book2.store("The Foundation Trilogy", "Isaac Asimov", 2);
book3.store("The Rainbow", "D.H.Lawrence", 1);
book1.show();
book2.show();
book3.show();
return 0;
}
Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
Posted: 2018年3月12日(月) 16:06
by tk-xleader
VisualC++ では、C++向けに
コード:
template<std::size_t N>errno_t strcpy_s(char(&)[N],const char*);
というシグネチャのstrcpy_sがオーバーロードされるのでcharの固定長配列であれば引数2個で大丈夫です。
Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
Posted: 2018年3月13日(火) 03:24
by hands
かずまさん、strcpy_sについて教えてくださりありがとうございます。またstringを使った書き方も知ることができて嬉しいです。
tk-xleaderさんにもその知識の深さには感服致します。皆さん本当にありがとうございます。
最後に一つだけ、お聞きしたいのですが、かずまさんが書かれたコードにある
かずま さんが書きました: ↑7年前
public:
void store(const string& t, const string& name, int num); // string
void show();
};
void card::store(const string& t, const string& name, int num) // string
{
title = t; // <-- strcpy(title, t);
author= name; // <-- strcpy(author, name);
number = num;
}
例えばconst string& tという部分のtは参照オブジェクトでよろしいのでしょうか。
この場合、何を何で初期化してるのでしょうか、titleをtで初期化でしょうか、それとも代入でしょうか。
見当はずれな問いでしたらすみません。
Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
Posted: 2018年3月14日(水) 07:20
by かずま
hands さんが書きました: ↑7年前
例えばconst string& tという部分のtは参照オブジェクトでよろしいのでしょうか。
この場合、何を何で初期化してるのでしょうか、titleをtで初期化でしょうか、それとも代入でしょうか。
「参照オブジェクト」という用語が私には理解できません。
const string& t と仮引数宣言された t は参照です。
メンバ関数 store の呼び出し元に stringオブジェクトが存在し、
そのオブジェクトを参照します。
title = t; により、呼び出し元の stringオブジェクトの値が
title に代入(コピー)されます。
呼び出し元は、
book1.store("Dune", ...
となっていて、
"Dune" は stringオブジェクトではないので、
ここで、string(const char *) というコンストラクタにより
一時的な stringオブジェクトが生成されてから
store が呼ばれます。
void store(string t, string name, int num); と宣言しても
プログラムは正しく動きます。
この場合、t は参照ではなく、stringオブジェクトです。
呼び出し時に string(const char *) コンストラクタで
t が初期化され、
title = t; により、t の値が title に代入されます。
呼び出し元が
string dune = "Dune";
book1.store(dune, ...
となっているとしたら、
const string& t の場合、t は dune そのものですが、
string t の場合、t は
コピーコンストラクタstring(const string&) により
dune のコピーとして初期化されます。
Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
Posted: 2018年3月15日(木) 05:22
by hands
かずまさん 詳しく教えてくださりありがとうございます。
まず、参照オブジェクトについてですが、新版明解C++入門編(柴田望洋著)に int& a = x; で型名の後ろに&を付けて宣言された変数aが参照オブジェクトです。と記述があります。参照について学習するページ内で数回、参照オブジェクトなる語が使われている為、一般的な表現かと思い使用しましたが、著書のなかでもキーワードとして太字で書かれてはおらず、また巻末の索引にもそうした語がないことから、著者独自の表現なのかも知れません。質問の意図が捉えにくくなった点、お詫びします。
ご回答頂いた内容ですが、初めて日が浅いためか一読した限りではなかなか理解できず、薄っすら「そうなんだ…」という感じでしたが、十数回(数えてないですけど)読んでようやく理解できたかなというところに達しましたので、今後勉強を続けながら確認していこうと思います。
あと、void store(string t, string name, int num); の方も試してちゃんと動くことを確認できました。それまではconst をつけないとエラーがでるんじゃないの?と思い込んでました。私はこの書き方が一番好きですね。
おかげさまで無事エラーも消せ、原因とその背景にある仕組みまで、私にとってはたいへん貴重な意見をいくつも伺うことができました。改めてお世話になりました皆さんにお礼申し上げます。細かい点においては未だ不明な箇所はありますが、疑問は学習する限り尽きることはないでしょうから、いたずらに長引かせるぬよう、本トピックはここいらで閉めさせていただればと思います。ありがとうございました。
Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
Posted: 2018年3月16日(金) 17:39
by naohiro19
<sstream>ヘッダーの std::stringstream というクラスを使えば
コード:
std::stringstream ss;
ss << "野原" << "一家";
std::string result = ss.str();
とすることで result には「野原」と「一家」が連結した状態でresultには「野原一家」いう文字列が入ります。
Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
Posted: 2018年3月27日(火) 03:45
by hands
naohiro19 さん stringstreamの情報をくださりありがとうございました。
また、別課題にあたっていたため、しばらく放置となったこと大変失礼いたしました。
そちらが一段落しましたので、コードをかいてみましたが、何分初心者でstringstreamはまったく存じ上げないばかりか、
そもそもクラスについてすら十分に把握できてないといったレベルですから、ちゃんと教えていただいたstringstreamが使えているのかがかなり怪しいです。
コードを載せますので、もし違っていれば正して頂けましたら参考になります。
コード:
// stringstream を使えば
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
class card {
stringstream title;
stringstream author;
int number;
public:
void store(string t, string name, int num);
void show();
};
void card::store(string t, string name, int num)
{
title.str (t);
author.str (name);
number = num;
}
void card::show()
{
cout << "本のタイトル: " << title.str() << "\n";
cout << "著者: " << author.str() << "\n";
cout << "冊数: " << number << "\n";
}
int main()
{
card book1, book2, book3;
book1.store("Dune", "Frank Herbert", 2);
book2.store("The Foundation Trilogy", "Isaac Asimov", 2);
book3.store("The Rainbow", "D.H.Lawrence", 1);
book1.show();
book2.show();
book3.show();
return 0;
}
Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
Posted: 2018年3月28日(水) 07:38
by かずま
string の代わりに stringstream を使うのは、やめたほうがいいでしょう。
コード:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
struct card1 {
char title[80];
char author[40];
int number;
};
struct card2 {
string title;
string author;
int number;
};
struct card3 {
stringstream title;
stringstream author;
int number;
};
int main()
{
cout << "sizeof(card1) = " << sizeof(card1) << "\n";
cout << "sizeof(card2) = " << sizeof(card2) << "\n";
cout << "sizeof(card3) = " << sizeof(card3) << "\n";
}
実行結果
コード:
VC++ x86 (32ビット)
sizeof(card1) = 124
sizeof(card2) = 52
sizeof(card3) = 360
VC++ x64 (64ビット)
sizeof(card1) = 124
sizeof(card2) = 72
sizeof(card3) = 504
cygwin g++ (GCC) 6.4.0
sizeof(card1) = 124
sizeof(card2) = 24
sizeof(card3) = 744
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
sizeof(card1) = 124
sizeof(card2) = 72
sizeof(card3) = 792
Re: E0167 型 "const char *" の引数は型 "char *" のパラメーターと互換性がありません
Posted: 2018年3月29日(木) 11:55
by hands
メモリ消費の観点からコードを記述した方が良さそうですね