Vscode で C コードをコンパイル・デバッグする#
vscode は単なるテキストエディタであるため、コンパイルとデバッグを行うためにtask.json
とlaunch.json
を設定する必要があります。(著者の C 環境は WSL 2(Ubuntu-20.04)に基づいて構築されています)
task.json
は以下の通りです:
{
"version": "2.0.0",
"tasks": [
{
"label": "Cプログラムをビルド",
"type": "shell",
"command": "gcc",
"args": [
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$gcc"
]
}
]
}
-
version:設定フォーマットのバージョンを指定します。現在は
"2.0.0"
のみサポートされています。 -
tasks:タスクの配列で、各要素は実行可能なタスクに対応します。
-
label:タスク名で、参照(例:
preLaunchTask
)や UI リストに表示されます。 -
type:タスクの種類で、一般的な値は
"shell"
(シェルで実行)または"process"
(実行可能ファイルを直接起動)です。 -
command:実行するコマンドまたはプログラム名です。
-
args:コマンドに渡す引数のリストで、組み込み変数の補間が使用できます。
"-g"
:デバッグシンボルを生成し、GDB などのデバッガがソースレベルでデバッグできるようにします。"${file}"
:現在アクティブなエディタで開いているファイルの完全パス(例:/home/user/main.c
)。"-o"
:GCC の出力リダイレクトオプションで、後続の出力ファイルのパスを指定します。"${fileDirname}/${fileBasenameNoExtension}"
:実行可能ファイルをソースファイルと同じディレクトリに出力し、ファイル名はソースファイルと同じですが拡張子はありません(例:/home/user/main
を出力)。
-
group:タスクを分類(例:
build
、test
)し、デフォルトグループ内のタスクとしてマークできます。 -
problemMatcher:コマンド出力を解析する方法を指定し、コンパイラのエラー / 警告を「問題」パネルにマッピングします。
launch.json
は以下の通りです:
{
"version": "0.2.0",
"configurations": [
{
"name": "WSLデバッグC",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}",
"args": [],
"stopAtEntry": true,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"miDebuggerArgs": "--nx",
"preLaunchTask": "Cプログラムをビルド"
}
]
}
C 言語のスコープ#
スコープはプログラム内で定義された変数が存在する領域であり、その領域を超えると変数にアクセスできなくなります。C 言語の変数には 3 種類があります:
- 関数内部のローカル変数
- すべての関数外部のグローバル変数
- 形式パラメータの関数パラメータ定義
1 ローカル変数#
ある関数またはブロック内部で宣言された変数はローカル変数と呼ばれます。これらはその関数またはコードブロック内部の文からのみアクセスでき、関数やブロック外部では認識されません。
2 グローバル変数#
グローバル変数は関数外部で定義され、通常はプログラムの先頭にあります。グローバル変数はプログラムのライフサイクル全体で有効であり、任意の関数内部からアクセスできます。つまり、グローバル変数は宣言後、プログラム全体で使用可能です。
もしローカル変数とグローバル変数の名前が同じ場合、関数内ではローカル変数が優先して使用されます。
3 形式パラメータ#
関数のパラメータである形式パラメータは、その関数内のローカル変数として扱われ、グローバル変数と同名の場合は優先して使用されます。
ポインタ#
ポインタはメモリアドレスであり、ポインタ変数はメモリアドレスを格納するための変数で、使用する前に宣言する必要があります。
type *var_name;
type
はポインタの基礎型、var_name
はポインタ変数の名前で、以下は有効なポインタ宣言です:
int *ip; /* 整数型のポインタ */
double *dp; /* double型のポインタ */
float *fp; /* 浮動小数点型のポインタ */
char *ch; /* 文字型のポインタ */
異なる型のポインタに対応するポインタの値の型は同じで、すべてメモリアドレスを表す 16 進数です。異なる型のポインタの違いは、ポインタが指す変数または定数のデータ型が異なることです。
1 ポインタの使用方法#
ポインタ変数を定義し、変数のアドレスをポインタに割り当て、ポインタ変数内のアドレスにアクセスします。
#include <stdio.h>
int main ()
{
int var = 20; /* 実際の変数の宣言 */
int *ip; /* ポインタ変数の宣言 */
ip = &var; /* ポインタ変数にvarのアドレスを格納 */
printf("var変数のアドレス: %p\n", &var );
/* ポインタ変数に格納されたアドレス */
printf("ip変数が格納しているアドレス: %p\n", ip );
/* ポインタを使用して値にアクセス */
printf("*ip変数の値: %d\n", *ip );
return 0;
}
//参考 菜鳥チュートリアル
2 NULL ポインタ#
ポインタ変数を宣言する際、確定したアドレスがない場合は、ポインタ変数に NULL を割り当てることができ、この時そのポインタは空ポインタと呼ばれます。