トップ回答者
C言語のプログラムがC++でコンパイルできない場合

質問
-
独学でC++を勉強している者です。画像処理について興味があったので
「C言語で学ぶ実践画像処理」という書籍の画像のフーリエ変換に関するサンプルコードを試してみたのですが、うまくコンパイルが通りません。
以下のようなコードはC++ではサポートされていないのでしょうか。
詳しい方いらっしゃいましたらご教授宜しくお願い致します。#include <stdio.h> #include <math.h> #define X_SIZE 128 /* 水平画素数,2のべき乗個 */ #define Y_SIZE 128 /* 垂直画素数,2のべき乗個 */ #define EXH 7 /* EXH = log2(水平画素数) */ #define EXV 7 /* EXV = log2(垂直画素数) */ #define MAX 255 /* 画像化の最大輝度 */ float ar[Y_SIZE][X_SIZE]; /* データ実数部 */ float ai[Y_SIZE][X_SIZE]; /* データ虚数部 */ float ff[Y_SIZE][X_SIZE]; /* フィルタの周波数特性 */ float sin_tbl[X_SIZE]; /* SIN計算用テーブル */ float cos_tbl[X_SIZE]; /* COS計算用テーブル */ int main() { float norm, max; int i, j, a, b, circ; char file1[80], file2[80]; printf(" Input image filename ? "); scanf("%s, file1"); printf(" Output image filename ? "); scanf("%s, file2"); fimage_read(ar, file1); /* 原画像読み込み */ for (i = 0; i < Y_SIZE; i++) { for (j = 0; j < X_SIZE; j++) { ai[i][j] = 0.0; } } printf("FFT started\n"); fft2(ar, ai, EXH, EXV, 1, sin_tbl, cos_tbl); /* FFT */ max = 0; for (i = 0; i < Y_SIZE; i++) { /* FFTイメージの作成 */ for (j = 0; j < Y_SIZE; j++) { norm = ar[i][j]*sr[i][j] + ai[i][j]*ai[i][j]; if (norm != 0.0) norm = log(norm) / 2.0; else ff[i][j] = norm; if (norm > max) max = norm; } } for (i = 0; i < Y_SIZE; i++) { for (j = 0; j < X_SIZE; i++) { ff[i][j] = ff[i][j]*MAX/max; } } fimage_write(ff, file2); /* FFT画像書き込み */ } fimage_read(fimage, filename) /* ディスクから画像を読み出しfloat配列にしまう */ float fimage[X_SIZE][Y_SIZE]; /* float画像配列 */ char *filename; /* ファイル名 */ { unsigned char buff[640]; FILE *fp; int i,j; if((fp=fopen(filename, "rb")) == NULL) { printf(" file open error\n "); exit(-1); } for (i = 0; i < Y_SIZE; i++) { fread(buff, 1, X_SIZE, fp); for (j = 0; j < X_SIZE; j++) { fimage[i][j] = (float)buff[j]; } } fclose(fp); } fimage_write(fimage, filename) /* float配列を画像にしてディスクに書き込む */ float fimage[X_SIZE][Y_SIZE]; /* float画像配列 */ char *filename; /* ファイル名 */ { unsigned char buff[640]; FILE *fp; int i,j; float data; if((fp=fopen(filename,"wb")) == NULL) { printf(" file open error\n "); exit(-1); } for (i = 0; i < Y_SIZE; i++) { for (j = 0; j < X_SIZE; j++) { data = fimage[i][j]; if (data > 255) data = 255; if (data < 0) data = 0; buff[j] = data; } fwrite(buff, 1, X_SIZE, fp); } fclose(fp); }
回答
-
C++は古い書式に対応していないようなので、新しい書式で書きなおすか、C言語としてコンパイルする必要があります。
なお、C言語としてコンパイルするには以下の設定を変更します。
プロジェクトのプロパティから、[構成プロパティ]->[C/C++]->[詳細設定]->[コンパイル言語の選択]で「C コードとしてコンパイル (/TC)」を選択します。
ファイルの拡張子は.cppのままでも大丈夫みたいです。
(旧書式だとIntelliSenceエラーが大量に出ますが、コンパイル・実行はできます。)
ただ、質問者様のコードは存在していない変数を使っていたりするようですので、旧書式とは関係のない部分でエラーも出るでしょう。
#追記です。
#上記の手順は、Visual Studio 2010の場合となります。 -
C++は古い書式に対応していないようなので
この書式に対応させるのは原理上不可能です。
fimage_read(fimage, filename)
float fimage[X_SIZE][Y_SIZE];
char *filename;
{
...;
}という書き方をした場合、プロトタイプ宣言は
int fimage_read();
になり、(引数なしではなく)引数が不明なままの宣言になります。
一方、C++言語には関数オーバーロードがあり、呼び出し側が渡した引数により呼び出される関数が決定されます。これが機能するためには、プロトタイプ宣言された関数の引数が不明な状態ではできません。
- 回答としてマーク TDN2010 2011年11月12日 14:04
-
いわゆる K&R と C89 (いわゆる ANSI-C) との区別も分からない人にあれこれ論評してないで、書き直してあげたら良いのにと思うけど
#include <stdio.h> #include <stdlib.h> #include <math.h> #define EXH 7 /* EXH = log2(水平画素数) */ #define EXV 7 /* EXV = log2(垂直画素数) */ #define X_SIZE (1<<(EXH)) /* 水平画素数,2のべき乗個 */ #define Y_SIZE (1<<(EXV)) /* 垂直画素数,2のべき乗個 */ #define MAX 255 /* 画像化の最大輝度 */ float ar[Y_SIZE][X_SIZE]; /* データ実数部 */ float ai[Y_SIZE][X_SIZE]; /* データ虚数部 */ float ff[Y_SIZE][X_SIZE]; /* フィルタの周波数特性 */ float sin_tbl[X_SIZE]; /* SIN計算用テーブル */ float cos_tbl[X_SIZE]; /* COS計算用テーブル */ void fimage_read(float[Y_SIZE][X_SIZE], char *); void fimage_write(float[Y_SIZE][X_SIZE], char *); void fft2(float[Y_SIZE][X_SIZE], float[Y_SIZE][X_SIZE], int, int, int, float[X_SIZE], float[X_SIZE]); int main() { float norm, max; int i, j; char file1[80], file2[80]; printf(" Input image filename ? "); scanf("%s", file1); printf(" Output image filename ? "); scanf("%s", file2); fimage_read(ar, file1); /* 原画像読み込み */ for (i = 0; i < Y_SIZE; i++) { for (j = 0; j < X_SIZE; j++) { ai[i][j] = 0.0; } } printf("FFT started\n"); fft2(ar, ai, EXH, EXV, 1, sin_tbl, cos_tbl); /* FFT */ max = 0; for (i = 0; i < Y_SIZE; i++) { /* FFTイメージの作成 */ for (j = 0; j < Y_SIZE; j++) { norm = ar[i][j]*ar[i][j] + ai[i][j]*ai[i][j]; if (norm != 0.0) norm = log(norm) / 2.0; else ff[i][j] = norm; if (norm > max) max = norm; } } for (i = 0; i < Y_SIZE; i++) { for (j = 0; j < X_SIZE; i++) { ff[i][j] = ff[i][j]*MAX/max; } } fimage_write(ff, file2); /* FFT画像書き込み */ return 0; } /* ディスクから画像を読み出しfloat配列にしまう */ void fimage_read( float fimage[Y_SIZE][X_SIZE], /* float画像配列 */ char *filename /* ファイル名 */ ) { unsigned char buff[X_SIZE]; FILE *fp; int i,j; if((fp=fopen(filename, "rb")) == NULL) { printf(" file open error\n "); exit(-1); } for (i = 0; i < Y_SIZE; i++) { fread(buff, 1, X_SIZE, fp); for (j = 0; j < X_SIZE; j++) { fimage[i][j] = (float)buff[j]; } } fclose(fp); } /* float配列を画像にしてディスクに書き込む */ void fimage_write( float fimage[Y_SIZE][X_SIZE], /* float画像配列 */ char *filename /* ファイル名 */ ) { unsigned char buff[640]; FILE *fp; int i,j; float data; if((fp=fopen(filename,"wb")) == NULL) { printf(" file open error\n "); exit(-1); } for (i = 0; i < Y_SIZE; i++) { for (j = 0; j < X_SIZE; j++) { data = fimage[i][j]; if (data > 255) data = 255; if (data < 0) data = 0; buff[j] = data; } fwrite(buff, 1, X_SIZE, fp); } fclose(fp); }
- 回答としてマーク TDN2010 2011年11月12日 14:04
すべての返信
-
C++は古い書式に対応していないようなので、新しい書式で書きなおすか、C言語としてコンパイルする必要があります。
なお、C言語としてコンパイルするには以下の設定を変更します。
プロジェクトのプロパティから、[構成プロパティ]->[C/C++]->[詳細設定]->[コンパイル言語の選択]で「C コードとしてコンパイル (/TC)」を選択します。
ファイルの拡張子は.cppのままでも大丈夫みたいです。
(旧書式だとIntelliSenceエラーが大量に出ますが、コンパイル・実行はできます。)
ただ、質問者様のコードは存在していない変数を使っていたりするようですので、旧書式とは関係のない部分でエラーも出るでしょう。
#追記です。
#上記の手順は、Visual Studio 2010の場合となります。 -
どれぐらい古いかというと、The C Programming Languageにありますが、first editionに書かれた書式なので1978年~ということになります。second edition(1988年)には既に現在の書式で改訂されています。著者の一人が先月亡くなりましたね。
質問者の方の年齢が知りたくなってしまいます。
-
外池と申します。
CとC++の文法の細かい相違について各論は私はよくわかりませんが、「方向性」のコメントをいくつか・・・。
言語もですが、画像処理で数学的に何をやっているか(FFTの部分や、結果をノーマライズしている部分)はご理解されていると思いますので、ご自身でC++の文法で書き直す努力が必要かと思います。この調子でいくと、fft2関数の中身はここに示されていませんが、大幅な書き直しが必要だと思います。
画像ファイルの読み取り、書き出しもまたしかり。ここでは、画像ファイルのフォーマットを理解した上で便利なライブラリを使いつつC++の文法で書き直しになろうかと。お手元にこのプログラムに適合するようなフォーマットの画像ファイルや画像ファイルを表示するソフトがあれば良いのですが、手軽に入手や作成ができる画像ファイル(jpg、tif、bmpなど)はこのプログラムで読み取っても意味を成さないのではないかと。
(ホームページを再開しました) -
C++は古い書式に対応していないようなので
この書式に対応させるのは原理上不可能です。
fimage_read(fimage, filename)
float fimage[X_SIZE][Y_SIZE];
char *filename;
{
...;
}という書き方をした場合、プロトタイプ宣言は
int fimage_read();
になり、(引数なしではなく)引数が不明なままの宣言になります。
一方、C++言語には関数オーバーロードがあり、呼び出し側が渡した引数により呼び出される関数が決定されます。これが機能するためには、プロトタイプ宣言された関数の引数が不明な状態ではできません。
- 回答としてマーク TDN2010 2011年11月12日 14:04
-
いわゆる K&R と C89 (いわゆる ANSI-C) との区別も分からない人にあれこれ論評してないで、書き直してあげたら良いのにと思うけど
#include <stdio.h> #include <stdlib.h> #include <math.h> #define EXH 7 /* EXH = log2(水平画素数) */ #define EXV 7 /* EXV = log2(垂直画素数) */ #define X_SIZE (1<<(EXH)) /* 水平画素数,2のべき乗個 */ #define Y_SIZE (1<<(EXV)) /* 垂直画素数,2のべき乗個 */ #define MAX 255 /* 画像化の最大輝度 */ float ar[Y_SIZE][X_SIZE]; /* データ実数部 */ float ai[Y_SIZE][X_SIZE]; /* データ虚数部 */ float ff[Y_SIZE][X_SIZE]; /* フィルタの周波数特性 */ float sin_tbl[X_SIZE]; /* SIN計算用テーブル */ float cos_tbl[X_SIZE]; /* COS計算用テーブル */ void fimage_read(float[Y_SIZE][X_SIZE], char *); void fimage_write(float[Y_SIZE][X_SIZE], char *); void fft2(float[Y_SIZE][X_SIZE], float[Y_SIZE][X_SIZE], int, int, int, float[X_SIZE], float[X_SIZE]); int main() { float norm, max; int i, j; char file1[80], file2[80]; printf(" Input image filename ? "); scanf("%s", file1); printf(" Output image filename ? "); scanf("%s", file2); fimage_read(ar, file1); /* 原画像読み込み */ for (i = 0; i < Y_SIZE; i++) { for (j = 0; j < X_SIZE; j++) { ai[i][j] = 0.0; } } printf("FFT started\n"); fft2(ar, ai, EXH, EXV, 1, sin_tbl, cos_tbl); /* FFT */ max = 0; for (i = 0; i < Y_SIZE; i++) { /* FFTイメージの作成 */ for (j = 0; j < Y_SIZE; j++) { norm = ar[i][j]*ar[i][j] + ai[i][j]*ai[i][j]; if (norm != 0.0) norm = log(norm) / 2.0; else ff[i][j] = norm; if (norm > max) max = norm; } } for (i = 0; i < Y_SIZE; i++) { for (j = 0; j < X_SIZE; i++) { ff[i][j] = ff[i][j]*MAX/max; } } fimage_write(ff, file2); /* FFT画像書き込み */ return 0; } /* ディスクから画像を読み出しfloat配列にしまう */ void fimage_read( float fimage[Y_SIZE][X_SIZE], /* float画像配列 */ char *filename /* ファイル名 */ ) { unsigned char buff[X_SIZE]; FILE *fp; int i,j; if((fp=fopen(filename, "rb")) == NULL) { printf(" file open error\n "); exit(-1); } for (i = 0; i < Y_SIZE; i++) { fread(buff, 1, X_SIZE, fp); for (j = 0; j < X_SIZE; j++) { fimage[i][j] = (float)buff[j]; } } fclose(fp); } /* float配列を画像にしてディスクに書き込む */ void fimage_write( float fimage[Y_SIZE][X_SIZE], /* float画像配列 */ char *filename /* ファイル名 */ ) { unsigned char buff[640]; FILE *fp; int i,j; float data; if((fp=fopen(filename,"wb")) == NULL) { printf(" file open error\n "); exit(-1); } for (i = 0; i < Y_SIZE; i++) { for (j = 0; j < X_SIZE; j++) { data = fimage[i][j]; if (data > 255) data = 255; if (data < 0) data = 0; buff[j] = data; } fwrite(buff, 1, X_SIZE, fp); } fclose(fp); }
- 回答としてマーク TDN2010 2011年11月12日 14:04
-
書き直した結果を提示してその違いを勉強してもらうのも一つの方法なら
直接結果を提示しないで自力で出来る方向にもって行くのも一つの方法だと思いますよ。どちらが良いという絶対的な評価は無いと思うので
自分の考えるやり方でアドバイスすれば良いだけだと思います。
そう考えるとソースを提示する前の一言は余計なのではと感じました。設定を変えてどうこうするのではなくて自分で内容を理解した上で書き換えても
悪くはなかったのではとも思いますけれど。
C++を勉強しようとしているのであれば、内容を理解した上でC++に移植するのも
勉強になるはずですし。独学なのか学校の勉強なのかはわかりませんけれど、
もう少し見守ってあげてもよかったのではとも思いますね。
解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。 -
いわゆる K&R と C89 (いわゆる ANSI-C) との区別も分からない人にあれこれ論評してないで、書き直してあげたら良いのにと思うけど
「差分を見て、その理由を調べて、自分のものにできる人」だとわかっているのであれば異論はありません。
ただ、失礼かもしれませんが、現状はそう思えなかったので、「どうすればコンパイルが通る形に持って行けるか」を知ってもらうことが重要かと考えていました。動くコードを提供したとき、それをそのまま利用して特に考えない人、差分を見て何らかの知見を得ようとする人がいます。
経験上、前者の方が多いので私は動くコードをそのまま出すことを避けます。ただ、質問内容からコードを書いた方が速いと判断できる何かがあれば、コードを出そうと思っていますね。今回の場合、参考書を元にコードを書き写していると言うことなので、同じ参考書から再度コードを書き写すことが予想されるので、書き換えのコツをつかんでもらうことが必要かと私は思っています。
ただ、その会得の手段として最適なのが、動くソースコードの提示だと判断できる根拠を、少なくとも私は見いだすことができませんでした。
質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。 -
短いコードなので、Cコードとして、コンパイルしてみました。 ファイル名: test.c とすると、コマンドライン(?)から、
> cl test.c
エラーコード: test.c(40) : error C2065: 'sr' : 定義されていない識別子です。
で、 sr => ar とすると、 warning C4716が2件。(実害ないですが)
と、リンクエラー: error LNK2019: 未解決の外部シンボル _fft2 が関数 _main で参照されました。
この書式のコードでもコンパイルが通るのがちょっと意外でした。
こちらの修正コード: error LNK2019: 未解決の外部シンボル _fft2 が関数 _main で参照されました。
さて、質問者の疑問点はどの辺なのでしょうか?
C++ としてコードを作成したいのか? それとも画像処理を試してみたいのでしょうか?
画像処理を試してみたいのでしたら、 Cのコードとしてコンパイルのするのが、早道でしょう。
C++を勉強したいのなら、もっと新しい参考書を探しましょう。
(自分の手元には、C時代の資料しかないで、最近のはわかりませんが、、、)
---------
最近の人では、コマンドラインとか、DOSプロンプトが通じない。プログラムを作っている人でも統合環境しか知らない人が、、。 ここで、コマンドラインと書いたけど、さて通じるか?
-
この書式のコードでもコンパイルが通るのがちょっと意外でした。
こちらの修正コード: error LNK2019: 未解決の外部シンボル _fft2 が関数 _main で参照されました。
C++言語と異なり、C言語ではプロトタイプ宣言は必須ではありません。一定のルールで引数がスタックに積まれ関数が呼び出されます(というコードがコンパイル時に生成されます)。リンク時に呼び出し先の関数を探し見つからなかったためにこのようなエラーになります。
# 「一定のルールで」があるためにprintf()にcharやshortを渡すことはできずintで受け渡しがされます。なのでfft2()が宣言されてないことは、致命的な問題ではありません。