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

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

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

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

7回答

4893閲覧

プログラミングの宣言と定義と命題

strike1217

総合スコア651

C

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

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

1クリップ

投稿2017/04/21 07:29

関数の場合、定義や宣言の違いが分かるのですが・・・
変数の場合、定義と宣言の違いが分かりません。

#define N 10

これは、「定義である」ということは分かります。
char buf[N]; このように使えるはずです。

しかし、以下のようになると、どっちがどっちなのか分かりません。

int a; int b = 0;

本によっては「宣言する」と言っていますが、他のサイトでは、「定義する」と言っているんですが、どっちですか??
What is the difference between a definition and a declaration?

コンパイラが参照を解決するために必要な構文要素が「宣言」であり、リンカが参照をリンクさせるのに必要な構文要素が「定義」ということのようです。

「参照を解決する」??ちょっとよくわかりません。

数学的に言うと、定義は変化しないので、上記のようなものはすべて「宣言」と見なせるような気がするんですが・・・
また、上記のような int b = 0; は前提事項としての公理ともいえるような気がするのですが・・・どうでしょうか?

あ・・・公理も変化してはいけないのかな??
プリプロセッサの部分は全て公理と言える気がするんですが・・・

また、if() などの条件分岐は命題関数と言えますよね????
なら定理もありますかね?
if() → TRUE の中カッコの中・・・かな

数学やプログラミングに詳しい方、ぜひ教えてください。

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

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

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

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

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

yohhoy

2017/04/21 07:37 編集

特定(C/C++)のプログラミング言語に関する質問なのでしょうか?それとも抽象的なプログラム意味論を話題にしているのでしょうか?(というより、どのような論法で”公理”や"命題"への論理飛躍が起きたのでしょう?)
strike1217

2017/04/21 07:38

if()の存在がただの場合分けで説明されると、少し納得がいかなかったので!数学モデルを模範としてプログラミング言語作成しているのなら、その関係性を知りたいと思ったからです。
strike1217

2017/04/21 07:39

すいません。タグについては、自分が一番よく使っている言語を載せてしまいました。
strike1217

2017/04/21 07:40

C/C++に限定された話ではありません。
strike1217

2017/04/21 07:46

あ、できればC/C++しかできないので、「その他の言語で説明されるとちょっとわからくなってしまう」というのもあります。
guest

回答7

0

私の解釈です。言語は問いません。

「宣言」は識別子(変数名や関数名等)がプログラムにおいて何であるかと言うことをしますものです。変数を表す場合もあれば関数を表す場合もありますし、もしかしたらクラスや型かもしれません。また、名前空間とスコープの決定にも関わり、グローバル変数とローカル変数を区別するには、どこで宣言されているのかで決まります。

「定義」はプログラムにおいてその識別子の中身です。関数であればその内容、定数であればその定まった値そのもの、エイリアスであれば元の何かのことです。また、定数ではない変数については、その領域が定まるところのみを定義している場合があります(中身が何かまでは定義されない)。

以上のことから次のようなことが言えます。

  • 「宣言」は矛盾がなければ複数回書いても問題ありません。対して、「定義」は一度きりである必要があります(言語によっては、同一内容であれば問題ないとなる物もありあます)。
  • 「宣言」があればコード内でその識別子を使うことができ、「定義」は必須ではありません。しかし、最終的に実行されるプログラム全体としてはどこかに「定義」がなければなりません。
  • **「宣言」と「定義」は兼ねることができます。ほとんどの場合において、「定義」は「宣言」を含んでいます。**ただし、「定義」の他に「宣言」が別途ある場合は、矛盾していてはいけません。
  • **「定義」は何を定義しているかは言語や対象によって異なります。**定数ではそれが指し示す値そのものまで定義する場合もありますが、定数ではない変数では(変更される可能性があるため)それが指し示す値そのもを定義することはできません。

さらに言語によっては色々事情が異なります。

  • 言語によっては「暗黙の宣言」があります。あるパターンの全ての識別子が暗黙的に「宣言」済みであると見なされます。(例: Rubyのインスタンス変数)
  • 言語によっては「仮定義」があります。他に確定した定義があれば「宣言」とみなされ、なければ「仮定義」が確定した「定義」として見なされます。(例: Cの初期化子が無くexternでないグローバル変数)
  • 言語によっては最初の代入が「宣言」や「定義」を兼ねる場合があります。(例: Pythonのローカル変数)
  • 言語によっては「宣言」が後に書かれても巻き上げ(そのスコープのトップにあると解釈される)て宣言済みと解釈される場合があります。(例: JavaScriptのvar変数)
  • 動的言語によってはコードの場所で識別子が解釈されるのではなく、実行時にそれまで宣言された物の中から識別子を探す場合があります(巻き上げと違って、識別子の認識自体が後からでも、実行時に認識済みならかまわないということ)。(例: Rubyの定数)

では、質問のコードがCだとして、どうなるかというと、これだけではわかりません。なぜなら、Cではスコープの場所によって事情が異なるからです。

C

1int a; 2int b = 0; 3int main(void) 4{ 5 return 0; 6}

上の場合は、int a;は「宣言」かつ「仮定義」であり、他に定義がないため「定義」になります。int b = 0;は「宣言」かつ「定義」です。なお、ここでは、記憶領域が定義されるだけであり、変数の値が定義されるわけではありません。値については初期値のみ与えられます。

C

1int a; 2int b = 0; 3int a = 1; 4int main(void) 5{ 6 return 0; 7}

上の場合は、int a = 1;という「定義」が他にあるため、「仮定義」であるint a;は「宣言」以上の意味を持ちません。

C

1int main(void) 2{ 3 int a; 4 int b = 0; 5 return 0; 6}

ローカル変数になると、両方とも「宣言」かつ「定義」になります。そのため、

C

1int main(void) 2{ 3 int a; 4 int b = 0; 5 int a = 0; 6 return 0; 7}

上のコードはコンパイルエラーになります。


最後に、Cのような命令型のプログラミング言語を数学的解釈をすることはかなり厳しいです。計算科学では数学から用語を取っていますが、命令型言語を通常の数学で表現することは困難です(例えば、x = x + 1をどう解釈すれば良いのだろうか?※)。関数型言語や宣言型言語でなければ、解釈にどこか無理が出てくると思います。「公理」や「命題」を数学的に考えているのであれば、命令型言語で考えることは辞めた方が無難かと思います。

x <- return $ x + 1としてなら解釈できないこともないかも知れません。

投稿2017/04/22 02:32

raccy

総合スコア21735

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

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

strike1217

2017/04/22 08:58

「グローバル変数とローカル変数を区別するには、どこで宣言されているのかで決まります。」 確かに、その通りです。 回答者の多くは、「私の解釈は・・・」とか「私の理解」という風に書いていますが、この質問の場合、絶対的な「これこれ・・・」というものはないんですかね?
raccy

2017/04/22 11:53

言語によっては仕様書や規格書に明記されている場合がありますが、言語によらず一般的なと言われるとそれぞれに多少のブレがあり、例外はどうしても出てくると思っています。
guest

0

ベストアンサー

C/C++の宣言と定義に関する私の理解です。

宣言は「名前の解決」です。
コンパイラーに対して「こういう名前の変数(あるいは関数、クラスなど)があるよ」と教えますが、宣言だけではその中身が何なのか、どこにあるのかまでは判りません。

定義は「仕様の確定」です。
その変数がどういう型でどのようにメモリに配置するのか、その関数がどんなコードを出力すればいいのか、そのクラスの中身はどのように記述されているのか、などをコンパイラーに教えるのが定義です。

定義すると自動的に名前の解決も行われるので、定義には宣言も含まれると言えます。ですので、文脈によっては定義のことを宣言と言ったりすることもありますが、混乱を避けるためには使い分けるのが望ましいとは思います。

投稿2017/04/21 12:16

catsforepaw

総合スコア5938

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

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

strike1217

2017/04/21 12:22

「変数を宣言する」ではなく、「変数名を宣言する」という言い方が正しいということですよね?
catsforepaw

2017/04/21 12:37

いいえ、「変数を宣言する」が正しいです。C++は名前修飾(マングリング)により、内部的な名前(アセンブラレベルのシンボル名)には型情報なども含まれます。「名前の解決」とは「修飾した名前を作る」ことです。
strike1217

2017/04/21 12:39

あ、そうなんですか!
strike1217

2017/04/21 13:45

シンボル解決を行う際の名前の指定が宣言ということですよね? 宣言が行われると、シンボルテーブル(.symtabセクション)に名前が載るだけということですか?
catsforepaw

2017/04/21 14:17

> 宣言が行われると、シンボルテーブル(.symtabセクション)に名前が載るだけということですか? おそらくELFファイルの.symtabのことだと思いますが、それはLinux固有の実行ファイル情報なので、C/C++の宣言とは直接の関係はありません。使われない限りはシンボル情報がオブジェクトファイルに出力されることはないと思います。 そうではなくて、コンパイラーがコンパイル処理の過程で名前を解決するのが宣言です。内部処理として名前照合データベースに登録するようなイメージです。
strike1217

2017/04/21 14:54

「名前照合データベースに登録する」、あああ~ なるほどです! では、定義とは、実際に作成したプログラムを実行した時に、使うものですか? メモリを確保する時とは、実行した時ですよね・・・?
catsforepaw

2017/04/21 15:19

C/C++は大抵コンパイラーなので、実行時というよりはコンパイル時ですね。 変数の定義は領域を確保するアセンブラコードが出力されますし、関数の定義はその処理内容のコードが出力されます。 クラス・構造体・共用体・列挙子は、それが使われるまでは何らかのコードとして出力されることはありませんが、コンパイル処理での「中身を確定させる」という意味において定義とみなせます。マクロ定義も同様ですね。
strike1217

2017/04/21 15:24 編集

宣言・定義、それぞれコンパイル時に出てくる話なのですね!!! わかりました。 定義 → アセンブリのあたり 宣言 → リンカのシンボル解決のあたり ということで良いでしょうか??
catsforepaw

2017/04/21 15:43

C/C++においては宣言と定義はコンパイル時の話ということで合っていますが、 > 定義 → アセンブリのあたり > 宣言 → リンカのシンボル解決のあたり > ということで良いでしょうか?? ちょっと違いますね。回答にも書いたように定義=「仕様の確定」、宣言=「名前の解決」です。 定義により仕様が確定することで、結果的に変数や関数なら何らかのアセンブラコードとして出力されますし、クラスや構造体などはその中身にアクセスすることができるようになりますし、中身が判ることでサイズも判るため、それを型にした変数を作る(=領域を確保する)ことができるようになります。 宣言だけだと、名前は解決するので、とりあえずその名前を利用できるようにはなりますが、例えば変数の外部参照宣言や関数プロトタイプ宣言では、それを使ってもコンパイル時にはエラーになりませんが、それを定義したオブジェクトと一緒にリンクしないとリンクエラーになりますよね。クラスや構造体などは宣言だけだとポインターとして利用することはできますが、変数として利用しようとするとコンパイルエラーになりますよね。
strike1217

2017/04/22 00:12

宣言 → アセンブリコードの出力のみというわけではない。 ということですね!
guest

0

こんにちは。

プログラミング言語一般ということですが、それでは「解」はないと思います。
そのプログラミング言語を定義した人がそれぞれの用語を定義するので、その用語の意味は言語毎に異なると思います。

例えば、C++はここに書かれてます。恐らく規格書もほぼ同じように書かれていると思います。

かなり厳密に定義されているようですが、正直複雑過ぎて良く分からんです。
C++の用語上「宣言」は「定義」を含むようですので全部ひっくるめて「宣言」と呼べば間違いになることはない筈です。
私自身は詳細まで記述されている宣言を「定義」と理解してます。C++的にも大きくは間違ってない筈と思います。

しかし、他の言語では通用しない筈です。

投稿2017/04/21 08:05

Chironian

総合スコア23272

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

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

strike1217

2017/04/21 08:07

あ~~ 他の言語でまた状況が変わってくるのですね・・・ 確かに複雑ですね。
guest

0

宣言 (declaration) と定義 (definition) の違い

名前 (識別子) の型をコンパイラに伝えるのが宣言で、その名前が参照している実体 (メモリ) を確保するのが定義です。

正確な内容は各言語の仕様書に書いていますと思いますが、私は(C/C++では)この説明が簡潔でしっくりきます。
ちなみに「変数 宣言 定義 違い」で検索して先頭に出てきたページです。

投稿2017/04/21 07:47

編集2017/04/21 07:50
can110

総合スコア38262

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

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

strike1217

2017/04/21 07:50

「その名前が参照している実体 (メモリ) を確保するのが定義です。」 ふむふむ・・・なるほどです!
strike1217

2017/04/21 07:53

もしかして、他の言語ではまた違うんですか?
can110

2017/04/21 07:54

ちなみに「#define N 10」は変数の宣言や定義とは別で、(プリプロセッサの)マクロ定義ですね。
strike1217

2017/04/21 07:56

あ、マクロ定義ですね。 そうでした。すいません。
can110

2017/04/21 07:57

違うと思いますが、確認はしていませんし、あまり気にしていません。 今まで使ってきた言語で、この違いを気にしたのはC/C++位です。
Chironian

2017/04/21 08:09

can110さん。 でも、クラス定義はメモリを確保しないのですよ。ほんとややこしいです。 strike1217さん。 マクロはプリプロセッサというある意味別の言語の話ですから、切り離した方が良いかもしれません。
can110

2017/04/21 08:15

>でも、クラス定義はメモリを確保しないのですよ。ほんとややこしいです。 ですね…。変数の説明だとしっくりくるんですが。 まあクラス定義は「実体 (メモリ) を確保する(ために必要な情報)」的な理解をしてます。
strike1217

2017/04/21 08:17

クラス定義はメモリ確保をしない?? そうなんですか?
Chironian

2017/04/21 08:26

class Foo { int data; };はクラス定義ですが、これだけではメモリは確保されません。 Foo foo;でメモリ確保されます。
strike1217

2017/04/21 08:28

オブジェクトを作成した時点で、確保されるんですね! クラス宣言という言い方が正しいということなんですかね?
strike1217

2017/04/21 08:31

メンバ変数、int data も Foo foo; とされるまでは、メモリ確保はされていない ということですか?
Chironian

2017/04/21 08:32

いえ、C++規格上、class Foo;は宣言、class Foo { int data; };は定義と決められています。
Chironian

2017/04/21 08:34 編集

class Foo { int data; };と書いただけでは、dataのメモリ領域は確保されていないですよ。そもそも、どこに確保します? スタック? グローバル領域?ヒープ?
strike1217

2017/04/21 08:35

ああ~~ なるほど! どこにオブジェクト作るかで、データ領域も変わるからですね!
HogeAnimalLover

2017/04/21 16:08

私も失礼ながら、こちらの考え方は不自然と思います。「宣言は語の存在を取り決めるもの」、「定義は語の意味を定めるもの」と区別しています。もちろん、メモリ領域の話にも副次的に関連はしますが、あくまでも副次的なものであって本質ではないです。 ちなみに、(本題ではないですが)変数を確保するメモリ領域はC/C++言語レベルで指定するものではないので、この部分も不適です。よく「ローカル変数はスタック領域に、グローバル変数はヒープ領域に配置される」とか見ますが、言語仕様レベルで定められているものではなく、「コンパイラの実装上、その傾向が強い」だけです。そんなルール存在しません。
Chironian

2017/04/21 17:08

HogeAnimalLoverさん。 それた話をここで続けるのは心苦しいので1点だけ。 標準規格では決まってなくても、事実上の標準が存在する部分は、事実上の標準から外れた処理系を想定しなくてもよいように私は思います。(事実上の標準から外れた処理系でも動く必要がある時は別ですが。) 例えば、ビットマップ・ファイルの保存処理を書く時、char型9ビット以上の処理系を想定しなくても良いと思いますし、スタックやグローバル領域、ヒープの件も同様と思うのです。(といいますか、そうでない実装を想像できないので、それを想定したプログラムを書けそうにないです。) この議題は結構奥が深いので、必要なら別途質問を立てて頂ければおつきあいさせて頂きます。
guest

0

変数の場合は宣言と定義に違いは事実上ありません。これらに違いが生じるのは関数とか構造体の場合です。変数の場合について考えても答えは出ません。

宣言はあくまでも「ユーザ定義の語」を取り決めるだけです。したがって、関数の場合はプロトタイプ宣言という概念(関数の名前と引数、戻り値だけを決めるもので、具体的な処理の記述は行わない)が存在し、定義と宣言が異なります。一方で、**「変数の場合は語を宣言すること自体が定義」**ですから、事実上、宣言と定義が同一となります。

もちろん、言語によっては違いもあるかもしれませんが、少なくともCの場合はこうなります。

投稿2017/04/21 11:37

編集2017/04/21 11:50
HogeAnimalLover

総合スコア4830

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

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

strike1217

2017/04/21 11:51

なるほど!! 分かりやすいです
guest

0

質問対象が過度に一般化されていて、答えようがない(or正解などない)ようにも感じます...

特定のプログラミング言語を取り上げるならば、"定義(definition)" や "宣言(declaration)" といった語の意味は、それぞれの「プログラミング言語仕様に依存する」としか言いようが無いです。


C/C++に限定された話ではありません。

とありますが、一応。(正確ではない)砕けた表現をするならば:

  • 定義:実体(変数ならメモリ領域/関数なら命令列)の存在を示し、同時にその中身(変数なら値/関数なら処理)も規定します。
  • 宣言:対応する実体がプログラム中のどこか別の場所に存在することを示します。

また、宣言と定義が同時に行われることもあります。たとえば初期値を指定する変数宣言は、その変数の定義でもあります。


コンパイラが参照を解決するために必要な構文要素が「宣言」であり、リンカが参照をリンクさせるのに必要な構文要素が「定義」ということのようです。

「参照を解決する」??ちょっとよくわかりません。

C/C++言語の仕様と、普通のC/C++処理系(=プリプロセッサ+コンパイラ+リンカ)では、上のような解釈になります。リンカ(linker)視点では:

  • 定義:名前のついた実体。変数ならメモリ確保(用の指示)、関数なら機械語命令列を生成する。
  • 宣言:実体がどこかに存在する。名前をもとに定義を探し出し、両者を紐付け、つまり参照を行う。

投稿2017/04/21 07:56

yohhoy

総合スコア6191

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

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

yohhoy

2017/04/21 08:00 編集

端的にいえば、プログラミング言語と数学的な"公理"や"命題関数"を突然結び付けて考えるのは無理があると思います。もちろん、あるプログラミング言語の機能や概念の裏側に、数学的な裏づけが存在する場合もあります。ただ、この質問文ではほとんど関係ない二つの話を、唐突に関連付けて混乱しているようにしか思えません。
strike1217

2017/04/21 08:00

int a = 0; //こっちは定義 a = 10; //呼び出したら、宣言 ということでしょうか?
strike1217

2017/04/21 08:05

実体の参照を行うのであれば、呼び出したら、宣言と言えますよね?
yohhoy

2017/04/21 08:21 編集

「int a = 0;」は「初期値0の変数aがそこに存在するという"定義"」であり、同時に「変数aがどこかに存在するという"宣言"」でもあります。なお「a=10;」は変数aを使っているだけで、定義とも宣言とも無関係です。 C/C++言語では基本的にソースコードを上から下に向かって順番にしか処理しないため、「ある変数を使うコード」→「その変数を定義」というソースコード記述がエラーになります。 そこで宣言と定義を分離し、「あらかじめ宣言だけしておく」→「ある変数を使うコード」→「その変数を定義」といった書き方が必要です。このときの宣言が前方宣言と呼ばれるものですが、最近のモダンなプログラミング言語ではそもそも前方宣言が必要ないことが多いです。言い換えると、C/C++以外のプログラミング言語では(概念的に)ソースコード全体を何度も自由に行き来して、プログラマがわざわざ宣言を書かなくとも、定義が見つかったらそれをちゃんと参照できます。
strike1217

2017/04/21 08:14

わ、、、わかりにくいですね。 a=10; 参照であっても、定義や宣言とは無関係なんですね! int a; この時点でメモリ上にはint型の領域が確保されていますよね? こちらは、定義ですか?
yohhoy

2017/04/21 08:27 編集

用語をものすごくあいまいに使っておられませんか?"参照"とは何を意味していますか? 答えられるほうだけ:C/C++固有の複雑なルールがあり、「int a;」が A)「定義 かつ 宣言」になるケース、B)「宣言のみ」となるケースの2種類が存在します。ただし、通常の利用方法ではA)になることのほうが多いと思います。詳細説明は省きます。
strike1217

2017/04/21 08:24

変数aの 定義 かつ 宣言 ・・・ そうなんですか!
strike1217

2017/04/21 08:30

コード内で一番最初に変数名を出す場合、定義として考えて良いということですよね・・・ 宣言より定義の方が分かりやすいです。
guest

0

int a;

int b = 0;

一般的には引用の上は宣言であり、下は初期化ありの宣言、というかな。
定義ではないです。

投稿2017/04/21 07:33

skittle

総合スコア21

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

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

strike1217

2017/04/21 07:35

あ~ 自分も定義ではないと思っているんですが、人によって違うんですよね・・・
skittle

2017/04/21 07:43

定義は使い道や指針をあらかじめ決めておくことであり、宣言は実際に使用することの取り決めか。日本語はややこしいですね。人により違うと思いますが、使う変数は”宣言”と私は勝手に決めています。これまで見てきた本でも同じでしたよ。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問