C++学習ノート1:キーワードConstとマクロ定義#define
15207 ワード
const constキーワード紹介constはconstantの略であり、1つの変数の前にconstで修飾すれば、その変数のデータにアクセスでき、修正できないことを意味する.すなわちconstは読み取り専用(readonly)を意味する.ルール:constが誰に近いかは、誰も修正できません.constは変数を修飾し、必ずこの変数に値を初期化しなければならない.初期化しなければ、後で初期化できない.本質:constは誰の後ろにあるかは修正できませんが、constは一番前にあると後ろに1人移動し、両者は等価です. constキーワードの役割は、パラメータが定数であることを宣言します.キーワードconstを合理的に使用することで、コンパイラが修正されたくないパラメータを自然に保護し、無意識なコード修正を防止し、バグの発生を減らすことができます. constキーワードアプリケーションは1つの変数が変更されることを阻止するために、constを使用することができて、このconst変数を定義する時、先に初期化する必要があって、後で彼を変える機会がありません;ポインタについては、ポインタ自体がconstであることを指定してもよいし、ポインタが指すデータがconstであることを指定してもよいし、両者が同時にconstであることを指定してもよい.1つの関数宣言では、constはパラメータを修飾することができ、関数内部で値を変更することはできません.クラスのメンバー関数の場合、constタイプとして指定する必要がある場合があります.これは通常の関数であり、クラスのメンバー変数を変更できないことを示します.クラスのメンバー関数では、戻り値が「左」でないようにconstタイプとして指定する必要がある場合があります.
const char*,char const*の違い
助記の方法:宣言を右から左に読む.char * const cp;//(*pointer toと読みます)cp is a const pointer to char const char*p;//p is a pointer to const char; char const * p;//p is a pointer to const char; C++にはconst*の演算子が入っていないため、constは前のタイプにしか属しません.
同様にC++にはconst*の演算子がないため、constは前のタイプに属するしかありません.
C++標準では、constキーワードはタイプまたは変数名の前に等価であることが規定されています.
ここまで言えば、以前のGoogleの筆記試験の問題を見ることができます.
以下の言い方が正しいのは、〔〕C A.関数foo()がpが指す文字列の内容を変更できないことである.B.関数foo()は、ポインタpをmallocが生成したアドレスに向けることができない.C.関数foo()は、pを新しい文字列定数に向けることができる.D.関数foo()はpをNULLに割り当てることができる.(?) この問題の答えについては諸説ある.上記の問題に対して、次のプログラムでテストすることができます.
結論:foo関数ではmain関数におけるpが指す新しい文字列定数を用いることができる.foo関数ではmain関数のpをNULLに向けることができます.foo関数では、main関数のpをmallocによって生成されたメモリブロックに向けることができ、mainでfreeで解放することができますが、警告があります.ただし、fooでmallocによって生成されたメモリブロックをpに指し示させたとしても、p[1]=‘x’は使用できない.このような文はpが指す内容を変える.fooでは,(pp)[1]=‘x’;このような文はpの内容を変える.したがって、gccはconstの字面の意味に従って制限されているだけで、すなわちconst charpのようなポインタに対して、後にpが実際にmallocのメモリや定数のメモリを指しても、p[1]='x'という文で内容を変えることはできないと感じている.しかし不思議なことに、fooではpに対してmallocのメモリを指した後、snprintfなどの関数で内容を修正することができます.
次のコードについて、
str 1,str 2,p 1,p 2の4つのアドレスが同じ値でないとstr 1とstr 2は異なり,p 1,p 2は同じである. str 1とstr 2は関係なく、文字定数配列であり、ちょうど格納されている値は同じです.「abc」およびstr 1 str 2は、いずれも定数領域に格納される.str 1 str 2のアドレスはstr 1[0]str 2[0]のアドレス、すなわち配列ヘッダ要素が存在するアドレスである. の後の2つの「abc」は、フォント値(定数)であるため、定数領域に格納されるが、p 1 p 2はスタックに格納される.ここで、p 1およびp 2は、同じ静的記憶領域を指す.つまり「abc」のアドレスです.
#define
#define変数定義値を前処理した後、セミコロンは使用できません.そうしないと計算エラーになりますが、プログラムはエラーを報告しません.
マクロ定義#defineと定数constの違い
#defiine
const
を選択します.
タイプなし
タイプの違いがある
あんぜんけんさ
セキュリティチェックがない場合、エラーが発生する可能性があります
タイプチェックあり
コンパイル時
デバッグできません
デバッグ可能
ライフサイクル
前処理フェーズ
コンパイル、実行フェーズ
きおくモード
メモリはコードセグメントに割り当てられません
メモリ割当て、データ・セグメント#メモリワリアテデータセグメント#
ドメインの定義
ドメインの定義なし
定義ドメイン内のみ有効
定義後に可変かどうか
可変
可変ではありません.定義時に値を割り当てる必要があります(extern修飾を除きます).
定義後にキャンセルできるかどうか
使用可能な#undefキャンセル
いいえ、定義ドメイン内で永続的に有効です.
関数パラメータとして使用できるかどうか
いけません
できる
1.タイプとセキュリティチェックの異なるマクロ定義は文字置換であり、データ型の違いがない.同時に、この置換にはタイプセキュリティチェックがなく、境界効果などのエラーが発生する可能性がある.const定数は定数の宣言で、タイプの違いがあり、コンパイル段階でタイプチェックを行う必要があり、いくつかの低レベルのエラーを避けることができます.具体例:
2.コンパイラが異なるマクロ定義を処理するのは「コンパイル時」の概念であり、前処理段階で展開され、マクロ定義をデバッグすることができず、ライフサイクルはコンパイル時期に終わる.const定数は「実行時」の概念であり、プログラムの実行で使用され、読み取り専用行データ3に類似する.ストレージ方式の異なるマクロ定義は直接置き換えられ、メモリは割り当てられず、プログラムのコードセグメントに格納される.const定数はメモリ割り当てが必要であり、プログラムのデータセグメントに格納される.ドメインの違いの定義
5.コードデバッグconst定数はデバッグできます.#defineはデバッグできません.プリコンパイル段階で置き換えられたためです.
6.定義後にconst制限子を変更できるかどうかは、後で変更できないので、定義時に初期値を付与する必要があります.そうしないと、この変数がexternで修飾された外部変数でない限り、エラーです.例:
7.定義後にマクロ定義を取り消すことができるかどうかは、#undefによって前のマクロ定義を失効させることができるconst定数定義後に定義ドメイン内で永続的に有効になる
8.関数パラメータマクロ定義が関数const定数にパラメータとして渡されないかは、関数のパラメータリストに表示されます.
const char*,char const*の違い
助記の方法:宣言を右から左に読む.char * const cp;//(*pointer toと読みます)cp is a const pointer to char const char*p;//p is a pointer to const char; char const * p;//p is a pointer to const char; C++にはconst*の演算子が入っていないため、constは前のタイプにしか属しません.
同様にC++にはconst*の演算子がないため、constは前のタイプに属するしかありません.
C++標準では、constキーワードはタイプまたは変数名の前に等価であることが規定されています.
const int n=5; //same as below
int const m=10;
const int *p; //same as below const (int) * p
int const *q; // (int) const *p
char ** p1;
// pointer to pointer to char
const char **p2;
// pointer to pointer to const char
char * const * p3;
// pointer to const pointer to char
const char * const * p4;
// pointer to const pointer to const char
char ** const p5;
// const pointer to pointer to char
const char ** const p6;
// const pointer to pointer to const char
char * const * const p7;
// const pointer to const pointer to char
const char * const * const p8;
// const pointer to const pointer to const char
ここまで言えば、以前のGoogleの筆記試験の問題を見ることができます.
const char *p="hello";
foo(&p); // foo(const char **pp)
以下の言い方が正しいのは、〔〕C A.関数foo()がpが指す文字列の内容を変更できないことである.B.関数foo()は、ポインタpをmallocが生成したアドレスに向けることができない.C.関数foo()は、pを新しい文字列定数に向けることができる.D.関数foo()はpをNULLに割り当てることができる.(?) この問題の答えについては諸説ある.上記の問題に対して、次のプログラムでテストすることができます.
#include
#include
#include
void foo(const char **pp)
{
// *pp=NULL;
// *pp="Hello world!";
*pp = (char *) malloc(10);
snprintf(*pp, 10, "hi google!");
// (*pp)[1] = 'x';
}
int
main()
{
const char *p="hello";
printf("before foo %s/n",p);
foo(&p);
printf("after foo %s/n",p);
p[1] = 'x';
return;
}
結論:foo関数ではmain関数におけるpが指す新しい文字列定数を用いることができる.foo関数ではmain関数のpをNULLに向けることができます.foo関数では、main関数のpをmallocによって生成されたメモリブロックに向けることができ、mainでfreeで解放することができますが、警告があります.ただし、fooでmallocによって生成されたメモリブロックをpに指し示させたとしても、p[1]=‘x’は使用できない.このような文はpが指す内容を変える.fooでは,(pp)[1]=‘x’;このような文はpの内容を変える.したがって、gccはconstの字面の意味に従って制限されているだけで、すなわちconst charpのようなポインタに対して、後にpが実際にmallocのメモリや定数のメモリを指しても、p[1]='x'という文で内容を変えることはできないと感じている.しかし不思議なことに、fooではpに対してmallocのメモリを指した後、snprintfなどの関数で内容を修正することができます.
次のコードについて、
const char str1[]=”abc”;
const char str2[]=”abc”;
const char *p1 = “abc”;
const char *p2 = “abc”;
str 1,str 2,p 1,p 2の4つのアドレスが同じ値でないとstr 1とstr 2は異なり,p 1,p 2は同じである.
#define
#define変数定義値を前処理した後、セミコロンは使用できません.そうしないと計算エラーになりますが、プログラムはエラーを報告しません.
#define age 12
#define age2 12;//
マクロ定義#defineと定数constの違い
#defiine
const
を選択します.
タイプなし
タイプの違いがある
あんぜんけんさ
セキュリティチェックがない場合、エラーが発生する可能性があります
タイプチェックあり
コンパイル時
デバッグできません
デバッグ可能
ライフサイクル
前処理フェーズ
コンパイル、実行フェーズ
きおくモード
メモリはコードセグメントに割り当てられません
メモリ割当て、データ・セグメント#メモリワリアテデータセグメント#
ドメインの定義
ドメインの定義なし
定義ドメイン内のみ有効
定義後に可変かどうか
可変
可変ではありません.定義時に値を割り当てる必要があります(extern修飾を除きます).
定義後にキャンセルできるかどうか
使用可能な#undefキャンセル
いいえ、定義ドメイン内で永続的に有効です.
関数パラメータとして使用できるかどうか
いけません
できる
1.タイプとセキュリティチェックの異なるマクロ定義は文字置換であり、データ型の違いがない.同時に、この置換にはタイプセキュリティチェックがなく、境界効果などのエラーが発生する可能性がある.const定数は定数の宣言で、タイプの違いがあり、コンパイル段階でタイプチェックを行う必要があり、いくつかの低レベルのエラーを避けることができます.具体例:
#define N 2+3 // N 5,
Ndouble a = N/2; // a 2.5, a 3.5
2.コンパイラが異なるマクロ定義を処理するのは「コンパイル時」の概念であり、前処理段階で展開され、マクロ定義をデバッグすることができず、ライフサイクルはコンパイル時期に終わる.const定数は「実行時」の概念であり、プログラムの実行で使用され、読み取り専用行データ3に類似する.ストレージ方式の異なるマクロ定義は直接置き換えられ、メモリは割り当てられず、プログラムのコードセグメントに格納される.const定数はメモリ割り当てが必要であり、プログラムのデータセグメントに格納される.ドメインの違いの定義
void f1 (){
#define N 12
const int n 12;
}
void f2 (){
cout<<N <<endl; // ,N ,
cout<<n <<endl; // ,n f1
}
5.コードデバッグconst定数はデバッグできます.#defineはデバッグできません.プリコンパイル段階で置き換えられたためです.
6.定義後にconst制限子を変更できるかどうかは、後で変更できないので、定義時に初期値を付与する必要があります.そうしないと、この変数がexternで修飾された外部変数でない限り、エラーです.例:
const int A=10; // 。
const int A; // , 。
extern const int A; // , extern 。
7.定義後にマクロ定義を取り消すことができるかどうかは、#undefによって前のマクロ定義を失効させることができるconst定数定義後に定義ドメイン内で永続的に有効になる
void f1(){
#define N 12
const int n = 12;
#undef N // , f1 ,N
#define N 21//
}
8.関数パラメータマクロ定義が関数const定数にパラメータとして渡されないかは、関数のパラメータリストに表示されます.