質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Q&A

解決済

3回答

3949閲覧

C言語の#defineと#includeの順番次第でエラーの有無が発生する理由

Maikaze0315

総合スコア14

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

0グッド

0クリップ

投稿2022/05/06 12:38

編集2022/05/06 12:40

C言語のエラーに関する質問です。
授業の課題で

2点pt1, pt2のx, y座標を
キーボードから読み込み(pt1, pt2ともy座標は正値を仮定),
pt2から出発し,x軸に接触した後pt1に至る経路で最短の経路
の経路長を求め,画面出力(表示)するプログラムを作成せよ.

といった課題が出ました。平方根を使うと思い、#include <math.h>を追加して書いたのですが、
このようなエラーが出ました。

c

1#define abs(x) (x < 0 ? x * -1 : x) 2#define max(x,y) (x > y ? x : y) 3#define min(x,y) (x < y ? x : y) 4 5#include <stdio.h> 6#include <string.h> 7#include <math.h> 8 9struct point { 10 double x, y; 11 12}; 13 14int main(void) 15{ 16 struct point pt1, pt2; 17 double s; 18 19 printf("Input pt1(x y) : "); 20 scanf("%lf %lf", &pt1.x, &pt1.y); 21 printf("Input pt2(x y) : "); 22 scanf("%lf %lf", &pt2.x, &pt2.y); 23 24 s = sqrt(pow(pt2.x - pt1.x, 2) + pow(pt1.y + pt2.y, 2)); 25 26 printf("%f", s); 27 28 return 0; 29}

エラー一覧
イメージ説明

いろいろ調べてみたところ#defineと#includeの順番を入れ替えると無事動きました。
がしかし、なぜ入れ替えると動いたのかという理由を調べてみても難しい用語がでてきて、それを調べてもまた難しい用語が出てきたりで困っています。
どなたか、ご教授願います。

稚拙な文で申し訳ないです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2022/05/06 12:53

出てきた難しい用語を書かないと、それを使って説明されたら困るでしょう。 簡単な用語だけで言うと、前から順に処理するために、前で定義されたものが上書きされるからです。
Maikaze0315

2022/05/06 13:59

おっしゃる通りです! わざわざ助かります。。。! 以後、気をつけます!
guest

回答3

0

  • マクロはプログラム全体の解釈の最初に展開され、それが終わってから各種の宣言や定義の解釈が始まる
  • マクロは C の構文を理解しない。 トークンの並びを置き換えるだけ
  • マクロはマクロを定義した場所以降の置き換えをする

というルールを元にして考えると理解できると思います。

状況を簡素化して例にしてみます。

c

1int foo(int x) { 2 return x; 3} 4 5#define foo(x) x 6 7int main(void) { 8 foo(1); 9}

これはエラーなくコンパイルできます。

上記のルールに従って「最初にマクロ展開される」というのを適用すると

c

1int foo(int x) { 2 return x; 3} 4 5int main(void) { 6 1; 7}

となって、問題は生じません。

ではマクロ定義と関数定義を入れ替えるとどうなるか?

つまり、

c

1#define foo(x) x 2 3int foo(int x) { 4 return x; 5} 6 7int main(void) { 8 foo(1); 9}

というプログラムを考えるとマクロ展開をした結果はこうなります。

c

1int int x { 2 return x; 3} 4 5int main(void) { 6 1; 7}

当然ながらこれは正しいプログラムになっていません。

こういうことが起きているわけです。

投稿2022/05/06 14:01

SaitoAtsushi

総合スコア5444

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

#define abs(x) なんとか というのは、その行以降にある abs(x)なんとか に置き換えるという意味です。それがヘッダの中でも起きます。

int __cdecl abs(_In_ int _X); は関数の宣言ですが、これが int __cdecl (_In_ int _X < 0 ? _In_ int _X * -1 : _In_ int _X); に置き換えられ、文法上めちゃくちゃなのでエラーになります。

#define をヘッダより後に書けばヘッダに影響はないので大丈夫ということです。

投稿2022/05/06 13:50

int32_t

総合スコア20845

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Maikaze0315

2022/05/06 13:57

既にabs()という関数があったからこうなってしまったんですね! 丁寧にありがとうございました!
guest

0

インクルードしているヘッダファイルの中で、どの関数がどのように定義されているのかわかりませんが、
関数absが例えば、下記のように宣言されていたとすると、

C

1int abs(int arg);

あなたの書いたマクロ定義により、これは、下記のように置換されて、Cの構文としては意味を成さないものになります。

C

1int (int arg < 0 ? int arg * -1 : int arg);

投稿2022/05/06 13:58

otn

総合スコア84505

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問