スポンサーリンク

このドキュメントの内容は、以下の通りです。

はじめに


C++言語 は、精力的に新しい機能が実装され、GNU GCCやClangなどの新しいバージョンが次々とリリースされます。次々と新しいプログラミング言語が開発され、便利なスクリプト言語が次々と登場していますが、C言語やC++言語は、いまでも根強い人気があるように思います。組み込み系で使われていたり、やはり実行速度が速い、といったメリットがあるからなのではないか、と思っています。

GNUGCCの 古い g++(コンパイラ) でコンパイルするときは、問題にならなかったけど、いつの間にかエラーになってコンパイルできなくなってしまった、というお話です。
どういうわけか、古いコンパイラを使わないといけない環境に長くいた影響なのか、現代のGNU g++の環境にソースコードを持ってきて、コンパイルしようとしたらエラーが続出でびっくりしました。
とりあえず、コンパイルしてくれてもいいじゃない?とか思うのですが、そういうわけにもいかないので、いろいろ直すことになりました。

今回 g++ で問題になったのは、デフォルト引数とプロトタイプ宣言と関数の実装のエラーです。

使っているコンパイラでコンパイルができても、 新しいコンパイラが出たときに、そのソースコードがコンパイルできるとは限りません。また、コンパイラの世代が何代も変わっていると、原因になるエラーが多すぎて、どこから手を付けて良いのかわからなくなってしまう可能性もあります。新しいコンパイラをできるだけ、試したほうがよいのだと思います。

2020年に少し記事を更新しました。新しい g++ のエラーや clang++ でのエラーも掲載しましたので、参考にしてください。
この記事の後半で紹介しますが、clang だと以下のエラーになります。

error: redefinition of default argument
note: previous definition is here


デフォルト引数とは


そもそも C++ の デフォルト引数とはなんでしょうか?

デフォルト引数は、関数を呼び出すときに、引数が指定されなかったときに使われる値です。デフォルト引数を利用することで、プログラミングをするときに、引数を省略することができます。

サンプルコード


たとえば、このようなソースコードを書きます。ここで重要なのは、デフォルト引数です。
関数 func に id という整数の引数があります。デフォルトの値は 0 です。

#include <iostream>
#include <cstdlib>
using namespace std;

void func ( int id = 0 );

void func ( int id = 0 ) {
	return;
}

int
main (int argc, char *argv[])
{

	func ( );

	exit (EXIT_SUCCESS);
}

コンパイルするとデフォルト引数でエラーが出る


サンプルのプログラムをコンパイルしてみます。

% g++ -Wall default_arg.cc
default_arg.cc: In function 'void func(int)':
default_arg.cc:7: error: default argument given for parameter 1 of 'void func(i'
default_arg.cc:5: error: after previous specification in 'void func(int)'
1で終了しました

英語のエラーが出てしまって、戸惑ってしまう方もおられるかもしれませんが、心配いりません。
g++コンパイラさんが親切にも
デフォルト引数が与えられているとか、
前に指定しているとか、ゴチャゴチャ言ってきます。

何が悪いのか?


C++のプログラムのプロトタイプ宣言部と関数宣言の両方で、デフォルト引数を設定しているのが問題でした。

具体的には、サンプルのプログラムのこの部分です。
void func ( int id = 0 );

void func ( int id = 0 ) {
	return;
}

そもそもこのレベルのプログラムでプロトタイプ宣言しなくてもいいじゃない、というのはなしです。
ヘッダファイルに宣言して、ほかのプログラムから利用させるということにしておいてください。

プロトタイプ宣言は、関数のパラメータがどうなっているのか、コンパイラにおしえるものなので、こちらにデフォルト引数を指定します。
ライブラリとして提供する場合、ライブラリを利用するプログラムは、ヘッダファイルをインクルードして使います。
そのときに、デフォルト引数が何個あるのか、知らないとコンパイラが困ります。
デフォルト引数として宣言していないと、必ず、引数をセットしないといけなくなります。

というわけで、関数宣言部分からデフォルト引数を削除します。

void func ( int id = 0 );

void func ( int id ) { // ここの id = 0 を id だけにしました。
	return;
}

これでC++のプログラムの問題は、解決しました。

2020年の環境では


2020年のコンパイラでは、どのようなエラーになるのか、紹介します。また、GNU GCC以外に Clang が使われている環境もあると思うので、Clang のケースについても紹介します。

vim のプラグインが表示しているものだと思われるのですが、プロトタイプ宣言部では、以下のエラーメッセージが出ています。

note: previous specification in 'void func(int)' here

void func ( int id = 0 );

また、関数の実装部分では、以下のエラーが出ています。

default argument given for parameter 1 of ‘'void func(int)' [-fpermissive]

void func ( int id = 0 ) {
        return;
}


実際に g++ のバージョン7.5.0 でコンパイルするとこのようになります。
薫 $ g++ --version
g++ (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
薫 $ g++ -Wall default-argument.cc
default-argument.cc: In function 'void func(int):
default-argument.cc:14:24: error: default argument given for parameter 1 of  void func(int)' [-fpermissiv]
 void func ( int id = 0 ) {
			^
default-argument.cc:12:6: note: previous specification in 'void func(int) here
 void func ( int id = 0 );
      ^~~~
[2]    276 exit 1     g++ -Wall default-argument.cc

g++のバージョン8だと以下の通りです。エラーメッセージは、 GNU GCC 7.5 系と変わらないように見えますね。
薫 $ g++8 --version
g++8 (FreeBSD Ports Collection) 8.2.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

薫 $ g++8 default-argument.cc
default-argument.cc:14:24: error: default argument given for parameter 1 of 'void func(int)' [-fpermissive]
 void func ( int id = 0 ) {
			^
default-argument.cc:12:6: note: previous specification in 'void func(int)' here
 void func ( int id = 0 );
      ^~~~

clang++ のバージョン 3.8.1 の場合と以下のエラーが出ます。
$ clang++38 default-argument.cc
default-argument.cc:14:17: error: redefinition of default argument
void func ( int id = 0 ) {
		^    ~
default-argument.cc:12:17: note: previous definition is here
void func ( int id = 0 );
		^    ~
1 error generated.

まとめ


  • C++のデフォルト引数の値は、ヘッダファイルの関数宣言部で行いましょう
  • プログラムの実装部分の関数の引数には、デフォルト引数の値を指定しません

スポンサーリンク
スポンサーリンク
 
いつもシェア、ありがとうございます!


もっと情報を探しませんか?

関連記事

最近の記事

人気のページ

スポンサーリンク
 

過去ログ

2020 : 01 02 03 04 05 06 07 08 09 10 11 12
2019 : 01 02 03 04 05 06 07 08 09 10 11 12
2018 : 01 02 03 04 05 06 07 08 09 10 11 12
2017 : 01 02 03 04 05 06 07 08 09 10 11 12
2016 : 01 02 03 04 05 06 07 08 09 10 11 12
2015 : 01 02 03 04 05 06 07 08 09 10 11 12
2014 : 01 02 03 04 05 06 07 08 09 10 11 12
2013 : 01 02 03 04 05 06 07 08 09 10 11 12
2012 : 01 02 03 04 05 06 07 08 09 10 11 12
2011 : 01 02 03 04 05 06 07 08 09 10 11 12
2010 : 01 02 03 04 05 06 07 08 09 10 11 12
2009 : 01 02 03 04 05 06 07 08 09 10 11 12
2008 : 01 02 03 04 05 06 07 08 09 10 11 12
2007 : 01 02 03 04 05 06 07 08 09 10 11 12
2006 : 01 02 03 04 05 06 07 08 09 10 11 12
2005 : 01 02 03 04 05 06 07 08 09 10 11 12
2004 : 01 02 03 04 05 06 07 08 09 10 11 12
2003 : 01 02 03 04 05 06 07 08 09 10 11 12

サイト

Vim入門

C言語入門

C++入門

JavaScript/Node.js入門

Python入門

FreeBSD入門

Ubuntu入門

セキュリティ入門

パソコン自作入門

ブログ

トップ


プライバシーポリシー