C++学習記録(001) - ヘッダ、名前空間

## C++学習記録(001) - ヘッダ、名前空間

Zybo用のSWをC++で作成したくなったので、C++を勉強することにした。

今回はヘッダと名前空間を勉強する。

毎回、最後には自分で練習問題を作成することにする。




## C++とは

C++とは、ざっと調べた感じでは下記のとおりだ。

* C言語にオブジェクト指向的拡張を施したプログラミング言語である。
* C言語と互換性がある。

* 低水準言語としても、高水準言語としても使える。




## 開発環境の導入手順

| 開発環境 | Microsoft Visual Studio Community 2022 Preview (64 ビット)<br>Version 17.0.0 Preview 4.1 |
| -------- | ------------------------------------------------------------ |


https://qiita.com/arta-crypt/items/75cbb052ec492f8d5a97



## ヘッダ

*Sample : Hello_world.cpp*

```c++
#include <iostream>

int main()
{
    std::cout << "Hello World!\n";
}
```



上記コードの1行目が、本サンプルプログラムで使用されているヘッダになります。

```c++
#include <iostream>
```



C言語では".h"がついていたが、C++ではつかない。

~~そのため、C言語ではヘッダファイルと呼んだが、C++では単にヘッダと呼んで区別されている。~~
ヘッダファイルとヘッダという用語の使い分けはない。>[ここを参照](https://timsong-cpp.github.io/cppwp/n3337/headers)
言語仕様上、標準ヘッダ名の命名習慣として".h"を付けるのをやめたようです。
[@SaitoAtsushi様](https://qiita.com/SaitoAtsushi)のご指摘を受け修正。

ちなみに、C言語の*\<stdio.h>*に相当するヘッダは*\<cstdio>*です。



> C 言語で使っていたヘッダファイルを C++ で使う場合には先頭に c をつけて、後尾の .h を省いたヘッダファイル名を使用するのが常識です。
>
> その違いは、名前空間です。
>
> C++ と同時に供給される標準ライブラリは全て std という名前のネームスペース（名前空間）内で定義されています。
>
> *参照：[C++マニアック][cpp_link5]*



C++ではヘッダを読み込むことにより、オブジェクトを使用できるようになる。

要するにC言語から拡張された機能を使用できるということだ。



## 名前空間(namespace)

名前空間とは、名前の衝突（重複）を防ぐための手段です。

この機能のおかげで汎用性のある名前を使用することができるようになります。(check,get,push等)

つまり安易に下記のように書いてしまうのは良くないということです。自作関数と標準入出力の名前が衝突（重複）してしまう危険があるからです。

```c++
using namespace std
```

参考：[@_EnumHack様の記事](https://qiita.com/_EnumHack/items/430da105a541f9ecd774)



しかしながらこの名前空間というのは本当に便利そうだ。

C言語をやっていると似たような名前の関数を作ってしまうことがある。それを簡単に回避できそうだ。実にスッキリしそう。



唐突に*using namespace*なんて書いてしまったが、これを使用することで記述量を減らすことができます。

たとえば、*printf*という関数は*\<cstdio>*というヘッダ内で、using宣言によって、*std*という名前空間からもアクセスできるように記述されています。

具体的には下記のようなコードになっていました(defineでの置き換えや、余計なコードは省いています)。



*Visual Studio 2022 : cstdio*

```c++
#include <stdio.h>

namespace std {
    using ::printf;
}
```



### 名前空間へのアクセス

ちなみに `using ::printf;` の書き方は、グローバル名前空間に属している*printf*を、using宣言によって*std*という名前空間からもアクセスできるようにする書き方です。（参照：[using 宣言](https://docs.microsoft.com/ja-jp/cpp/cpp/using-declaration?view=msvc-160&viewFallbackFrom=vs-2019)）

この*printf*を使用する場合は下記のように書くことになります。

```c++
#include <cstdio>

int main() {
    std::printf("Hello World!\n");
}
```

`::` はスコープ解決演算子と呼びます。（参照：[スコープ解決演算子: ::](https://docs.microsoft.com/ja-jp/cpp/cpp/scope-resolution-operator?view=msvc-160)）



しかしながら、実は `#include <stdio.h>` の書き方からもわかるように単に、この場合は `printf("Hello World!\n")` と書くことも可能です。



## 練習問題



### 問題1

cstdioというヘッダを使用して、printf関数を用いて、標準出力に"Hello World!"と表示するプログラムを書きなさい。



### 問題2

stdio.hというヘッダを使用して、printf関数を用いて、標準出力に"Hello World!"と表示するプログラムを書きなさい。



### 問題3

my_cstdioという名前空間を作成し、printf関数を作成した名前空間からアクセスできるようにする。

my_cstdioという名前空間からprintfにアクセスし、標準出力に"Hello World!"と表示するプログラムを書きなさい。



## 解答



### 問題１解答

ソースコード例

```c++
#include <cstdio>

int main()
{
    std::printf("Hello World!\n");
}
```

実行結果

![debug_console_001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1894918/45887466-eb0a-f7eb-636d-d4cab86295d2.png)



### 問題２解答

ソースコード例

```c++
#include <stdio.h>

int main()
{
    printf("Hello World!\n");
}
```

実行結果

![debug_console_002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1894918/8da5e71e-57b2-4167-effc-c843dd6f0c15.png)



### 問題3解答

ソースコード例

```c++
#include <stdio.h>

namespace my_cstdio {
    using ::printf;
}


int main()
{
    my_cstdio::printf("Hello World!\n");
}
```

実行結果

![debug_console_003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1894918/98ef2f1b-584c-901d-8b16-c4343ca919cb.png)



## (ex) 実験

cstdioとstdio.hを両方インクルードして、printfを使用した場合どうなるか実験してみる。



### 予想

stdio.hが二重インクルードされてしまわないようにガードされているだろうし、

printfはグローバル名前空間からアクセスできるから、普通にビルドできて、問題なく"Hello World!"が表示される。



### 実験コード

```c++
#include <stdio.h>
#include <cstdio>

int main(){
    printf("Hello World!\n");
}
```



### 結果

![debug_console_004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1894918/4ede926a-6eb3-f3e7-9892-68b66736ff04.png)

予想通りの結果となった。問題なくコンパイルが完了し、実行された。

stdio.hの中身を見てみると `#pragma once` でインクルードガードされていました。




## 参考

[cpprefjp - C++日本語リファレンス][cpp_link1]

[Wikipedia][cpp_link2]

[ゼロから学ぶ C++][cpp_link3]

[一週間で身につくC++言語の基本][cpp_link4]

[C++マニアック][cpp_link5]

[Programming Place Plus　新C++編][cpp_link6]

[Programming Place Plus　C++編][cpp_link7]



[cpp_link1]:https://cpprefjp.github.io/	"cpprefjp-C++日本語リファレンス"
[cpp_link2]:https://ja.wikipedia.org/wiki/C%2B%2B	"Wikipedia"
[cpp_link3]:https://rinatz.github.io/cpp-book/	"ゼロから学ぶC++"
[cpp_link4]:https://cpp-lang.sevendays-study.com/	"一週間で身につくC++言語の基本"
[cpp_link5]:http://stlalv.la.coocan.jp/FirstProgram.html	"C++マニアック"
[cpp_link6]:https://programming-place.net/ppp/contents/cpp2/index.html	"ProgrammingPlacePlus　新C++編"
[cpp_link7]:https://programming-place.net/ppp/contents/cpp/index.html	"ProgrammingPlacePlus　C++編"