閉じる

C言語のgetenvで環境変数を取得する使い方と例

C言語のgetenvは、プロセスに設定された環境変数を文字列で取得できる標準関数です。

設定ファイルを用意せずに挙動を切り替えたり、PATHや一時ディレクトリなど実行環境のパスを知るのに便利です。

本記事では基本の呼び出し方、NULLの扱い、値の安全な使い方、OSごとの違いを、初心者の方にもわかりやすく解説します。

なお、扱うテーマは「環境変数を取得する(getenv)」に限定します。

C言語のgetenvとは?

環境変数を文字列で取得

getenvは、引数で指定した名前の環境変数を探し、その値をヌル終端された文字列のポインタとして返します。

例えばPATHHOME(Linux/macOS)、USERPROFILE(Windows)などが代表的です。

存在しない環境変数名を指定した場合はNULLが返ります

仕様の要点

  • 戻り値はライブラリ内部の領域を指すポインタです。値を書き換えたり直接freeしたりしてはいけません
  • 同一プロセス内で環境が更新されると(例: POSIXのsetenvputenv)、指すアドレスや内容が変わる可能性があります。

ヘッダー

getenv<stdlib.h>に宣言されています。

標準出力に表示する実例では<stdio.h>も使います。

C言語
#include <stdlib.h>  // getenv
#include <stdio.h>   // printf など

戻り値とNULL

char *が返り値です。

環境変数が見つからなければNULLになります。

C言語では文字列の長さは事前に分からないため、値をコピーする場合はstrlenで長さを測ってから領域を確保します。

NULLチェックを忘れると実行時エラーの原因になるので、必ず確認しましょう。

getenvの基本の使い方

最小サンプル

最小限の例として、OSに応じてホームディレクトリの環境変数(WindowsはUSERPROFILE、Linux/macOSはHOME)を取得して表示します。

C言語
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    // OSごとに代表的なホーム環境変数名を切り替えます
    // Windows: USERPROFILE, Linux/macOS: HOME
#ifdef _WIN32
    const char *name = "USERPROFILE";
#else
    const char *name = "HOME";
#endif

    // getenvで値を取得
    const char *value = getenv(name);

    // NULLかどうかを必ず確認
    if (value != NULL) {
        printf("%s=%s\n", name, value);
    } else {
        printf("%s is not set.\n", name);
    }
    return 0;
}
実行結果
HOME=/home/alice

NULLチェック

存在しない環境変数はNULLが返るため、必ずチェックします。

NULLのままprintf("%s")などに渡すと未定義動作になります。

C言語
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    const char *name = "NOT_EXIST_ENV";
    const char *value = getenv(name);

    if (value == NULL) {
        // 見つからなかった場合の扱いを決めておく
        // 例: デフォルト値を使う、エラー終了する、など
        printf("%s is not set (NULL returned).\n", name);
    } else {
        printf("%s=%s\n", name, value);
    }
    return 0;
}
実行結果
NOT_EXIST_ENV is not set (NULL returned).

取得した文字列は変更しない

戻り値のポインタが指す領域はライブラリ側の所有物です。

値を直接変更すると未定義動作になるため、必要があれば自分のバッファにコピーしてから編集します。

C言語
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    const char *src = getenv("PATH");
    if (src == NULL) {
        puts("PATH is not set.");
        return 0;
    }

    // 直接書き換えはNG: src[0] = 'X'; // 未定義動作
    // 安全な方法: 自分のバッファにコピーしてから操作する
    size_t len = strlen(src);
    char *copy = (char *)malloc(len + 1);
    if (!copy) {
        fputs("malloc failed.\n", stderr);
        return 1;
    }
    strcpy(copy, src); // コピー

    // 例として、コピーの先頭にタグを付ける
    // (実践ではsnprintfで安全に連結する方が推奨です)
    printf("Original PATH (truncated view): %.60s...\n", src);
    printf("Copied PATH (truncated view):   %.60s...\n", copy);

    // コピーを編集してもOK
    if (len > 0) copy[0] = '#';
    printf("Edited copy (truncated view):   %.60s...\n", copy);

    free(copy);
    return 0;
}
実行結果
Original PATH (truncated view): /usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin...
Copied PATH (truncated view):   /usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin...
Edited copy (truncated view):   #sr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin...

大文字/小文字の注意

POSIX系(Linux/macOS)では環境変数名は大文字小文字を区別します。

一方Windowsでは大文字小文字を区別しません

そのため、移植性を意識して慣例的な大文字名を使うのが安全です。

C言語
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    const char *upper = getenv("PATH");
    const char *mixed = getenv("Path");

#ifdef _WIN32
    printf("On Windows, PATH: %s\n", upper ? upper : "(NULL)");
    printf("On Windows, Path: %s\n", mixed ? mixed : "(NULL)");
#else
    printf("On POSIX, PATH: %s\n", upper ? upper : "(NULL)");
    printf("On POSIX, Path: %s\n", mixed ? mixed : "(NULL)"); // ふつうはNULL
#endif
    return 0;
}

実行結果(例: Linux/macOS)

実行結果
On POSIX, PATH: /usr/local/bin:/usr/bin:/bin
On POSIX, Path: (NULL)

実行結果(例: Windows)

実行結果
On Windows, PATH: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem
On Windows, Path: C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem

環境変数の取得例

PATHを読む

PATHはコマンド探索用ディレクトリの一覧です。

Linux/macOSは:区切り、Windowsは;区切りです。

分割する場合はstrtokなどを使いますが、分割の前に必ずコピーを作ることが重要です(戻り値を直接書き換えないため)。

C言語
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    const char *path = getenv("PATH");
    if (!path) {
        puts("PATH is not set.");
        return 0;
    }

    // デリミタをOSごとに選択
#ifdef _WIN32
    const char delim = ';';
#else
    const char delim = ':';
#endif
    char delim_str[2] = { delim, '
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
const char *path = getenv("PATH");
if (!path) {
puts("PATH is not set.");
return 0;
}
// デリミタをOSごとに選択
#ifdef _WIN32
const char delim = ';';
#else
const char delim = ':';
#endif
char delim_str[2] = { delim, '\0' };
// PATHは書き換え不可なので、コピーしてからstrtokする
char *buf = (char *)malloc(strlen(path) + 1);
if (!buf) {
fputs("malloc failed.\n", stderr);
return 1;
}
strcpy(buf, path);
printf("PATH entries:\n");
int i = 0;
for (char *tok = strtok(buf, delim_str); tok != NULL; tok = strtok(NULL, delim_str)) {
printf("  [%d] %s\n", i++, tok);
}
free(buf);
return 0;
}
' }; // PATHは書き換え不可なので、コピーしてからstrtokする char *buf = (char *)malloc(strlen(path) + 1); if (!buf) { fputs("malloc failed.\n", stderr); return 1; } strcpy(buf, path); printf("PATH entries:\n"); int i = 0; for (char *tok = strtok(buf, delim_str); tok != NULL; tok = strtok(NULL, delim_str)) { printf(" [%d] %s\n", i++, tok); } free(buf); return 0; }

実行結果(例: Linux/macOS)

実行結果
PATH entries:
  [0] /usr/local/bin
  [1] /usr/bin
  [2] /bin
  [3] /usr/local/sbin
  [4] /usr/sbin

HOME/USERPROFILEを読む

ユーザーのホームディレクトリは、Linux/macOSはHOME、WindowsはUSERPROFILEが一般的です。

WindowsではHOMEDRIVEHOMEPATHの組み合わせが使える場合もあります。

C言語
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
#ifdef _WIN32
    const char *home = getenv("USERPROFILE");
    if (home) {
        printf("Home: %s\n", home);
        return 0;
    }
    // フォールバック: HOMEDRIVE + HOMEPATH
    const char *drive = getenv("HOMEDRIVE");
    const char *path  = getenv("HOMEPATH");
    if (drive && path) {
        size_t len = strlen(drive) + strlen(path) + 1;
        char *combined = (char *)malloc(len);
        if (!combined) {
            fputs("malloc failed.\n", stderr);
            return 1;
        }
        // 例: "C:" + "\Users\alice" -> "C:\Users\alice"
        strcpy(combined, drive);
        strcat(combined, path);
        printf("Home (fallback): %s\n", combined);
        free(combined);
    } else {
        puts("Home directory is not set.");
    }
#else
    const char *home = getenv("HOME");
    if (home) {
        printf("Home: %s\n", home);
    } else {
        puts("HOME is not set.");
    }
#endif
    return 0;
}
実行結果
Home: /home/alice

TEMP/TMPを読む

一時ファイルの保存先は、POSIXはTMPDIR(なければ/tmp)、WindowsはTMPまたはTEMPが一般的です。

C言語
#include <stdio.h>
#include <stdlib.h>

int main(void) {
#ifdef _WIN32
    const char *tmp = getenv("TMP");
    if (!tmp) tmp = getenv("TEMP");
    if (!tmp) tmp = "C:\\Windows\\Temp"; // 最終フォールバック(存在しない可能性もある点に注意)
#else
    const char *tmp = getenv("TMPDIR");
    if (!tmp) tmp = "/tmp"; // 代表的なデフォルト
#endif

    printf("Temp directory: %s\n", tmp);
    return 0;
}
実行結果
Temp directory: /tmp

WindowsとLinuxの違い

名前の大小文字の扱いと、PATH区切り、代表的変数名に違いがあります。

移植性を高めるには、OSごとの慣例名を使い、区切り文字を条件コンパイルで切り替えます。

項目Linux/macOS(POSIX)Windows備考
変数名の大文字小文字区別する区別しない慣例的に大文字を使う
PATHの区切り:;例: “/usr/bin:/bin” と “C:\Windows;C:\Windows\System32”
ホーム変数HOMEUSERPROFILE(推奨)、HOMEDRIVE+HOMEPATHGUI起動アプリでは例外的ケースに注意
一時ディレクトリTMPDIR(なければ/tmp)TMP または TEMPAPI側に専用関数がある場合も
パス区切り文字/\C文字列ではバックスラッシュのエスケープに注意

Windows固有の補足: Microsoft Cランタイムには_dupenv_sgetenv_sといった拡張もあります。

Unicodeを扱う場合は_wgetenvやWinAPIのGetEnvironmentVariableWも検討します。

動作確認の準備

macOS/Linux(Bash)で設定

Bashで一時的に環境変数を設定するにはexportを使います。

シェルを閉じると消えます。

Shell
# 一時設定
export SAMPLE_VALUE="hello"
echo "$SAMPLE_VALUE"

# 解除
unset SAMPLE_VALUE

永続化したい場合はシェルの初期化ファイル(例: ~/.bashrc, ~/.zshrc)に追記します。

Shell
echo 'export SAMPLE_VALUE="hello"' >> ~/.bashrc
# 反映
source ~/.bashrc

Windows(PowerShell)で設定

PowerShellでは$env:変数名でそのセッション限定の設定ができます。

PowerShell
# 一時設定
$env:SAMPLE_VALUE = "hello"
Write-Output $env:SAMPLE_VALUE

# 解除
Remove-Item Env:SAMPLE_VALUE

永続化はsetxを使います。

現在のセッションには即時反映されない点に注意してください。

PowerShell
# 永続設定(ユーザー環境)
setx SAMPLE_VALUE "hello"

Windows(CMD)で設定

CMDではsetが一時設定、setxが永続設定です。

Batch File
:: 一時設定
set SAMPLE_VALUE=hello
echo %SAMPLE_VALUE%

:: 解除
set SAMPLE_VALUE=

:: 永続設定(次回のセッションから有効)
setx SAMPLE_VALUE hello

一時設定と永続設定

一時設定は「現在のプロセス(シェル)とそこから起動された子プロセスにだけ影響」し、シェルを閉じると消えます。

永続設定は「システムやユーザーのプロファイルに保存」され、新しいシェルや再ログイン後に有効になります。

アプリの動作確認では、まず一時設定で試し、必要に応じて永続化すると安全です。

また機密情報を環境変数に保存するのは避けるか、最小限に留めてください。

まとめ

getenvは環境変数を簡単に取得できる標準関数で、設定ファイルなしに挙動を切り替えたいときに役立ちます。

ポイントは次の通りです。

まず戻り値がNULLかを必ず確認し、取得した文字列は変更しないこと。

編集したい場合は自前のバッファにコピーします。

さらにOSごとの違い(PATHの区切り、HOME/USERPROFILE、TEMP/TMP、大小文字の扱い)を理解し、条件コンパイルやフォールバックで移植性を高めましょう。

必要に応じてWindows固有の_dupenv_sやUnicode対応APIも検討してください。

これらを押さえれば、PATHの分解、ホームディレクトリや一時ディレクトリの決定など、実用的な処理を堅牢に実装できます。

この記事を書いた人
エーテリア編集部
エーテリア編集部

プログラミングの基礎をしっかり学びたい方向けに、C言語の基本文法から解説しています。ポインタやメモリ管理も少しずつ理解できるよう工夫しています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!