欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

為什么獲取環(huán)境變量getenv小心有坑

 更新時(shí)間:2025年03月26日 14:07:20   作者:半路殺出來(lái)的小黑同學(xué)  
這篇文章主要介紹了獲取環(huán)境變量getenv小心有坑問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

一、背景

在工作中,所做的項(xiàng)目需要涉及兩個(gè)不同語(yǔ)言( P/Invoke)的信息傳遞。最后選定了一種環(huán)境變量的傳遞方式,但這也遇到了getenv帶來(lái)的大坑!

問(wèn)題現(xiàn)象

我們?cè)贑#的exe主流程中通過(guò)DllImport,對(duì)環(huán)境變量進(jìn)行了設(shè)置。隨后我通過(guò)DllImport來(lái)引入C++的函數(shù)定義到托管函數(shù)內(nèi)存中,然后我再使用此環(huán)境變量時(shí),發(fā)現(xiàn)在C++中根本不存在。

而當(dāng)查看官方文檔對(duì)于Environment.SetEnvironmentVariable()的(定義)[https://learn.microsoft.com/zh-cn/dotnet/api/system.environment.getenvironmentvariables?view=net-5.0&viewFallbackFrom=netstandard-1.0]時(shí),可以發(fā)現(xiàn),其功能為:創(chuàng)建、修改或刪除存儲(chǔ)在當(dāng)前進(jìn)程中的環(huán)境變量。而通過(guò)DllImport加載的C++代碼也明明是同一進(jìn)程呀,為何會(huì)出現(xiàn)此種原因???

二、實(shí)驗(yàn)

在C#中,設(shè)置環(huán)境變量基本就Environment.SetEnvironmentVariable()一種方法,而在CPP中有三種方法:

  • 標(biāo)準(zhǔn)庫(kù)方法:getenv 函數(shù)
  • Windows.h庫(kù)方法:_wgetenv 函數(shù)以及GetEnvironmentVariable 函數(shù)

首先,先說(shuō)結(jié)果:

【dotnet構(gòu)建的EXE + MingW構(gòu)建的DLL】

  • Environment.SetEnvironmentVariable()函數(shù)+ getenv 函數(shù)

  • Environment.SetEnvironmentVariable()函數(shù)+ _wgetenv 函數(shù)

  • Environment.SetEnvironmentVariable()函數(shù)+ GetEnvironmentVariable 函數(shù)

【dotnet構(gòu)建的EXE +MSVC構(gòu)建的DLL】

  • Environment.SetEnvironmentVariable()函數(shù)+ getenv 函數(shù)

下面是我們的測(cè)試代碼:

  • C++測(cè)試的源代碼:
// getenv函數(shù)所需頭文件
#include <cstdlib>
#include <iostream>
// _wgetenv函數(shù)所需頭文件
#include <cwchar>
#include <string>
// GetEnvironmentVariable函數(shù)所需頭文件
#include <windows.h>

extern "C" {
    __declspec(dllexport) const char* get() {
        const char* path_env = std::getenv("PATH_TEST");
        return path_env;
    }
}

extern "C" {
    __declspec(dllexport) const char* get_wide() {
        wchar_t* wpath_env = _wgetenv(L"PATH_TEST");
        if (wpath_env != nullptr) {
            static std::string path_env;
            path_env.assign(wpath_env, wpath_env + wcslen(wpath_env));
            return path_env.c_str();
        }
        return nullptr;
    }
}

extern "C" {
    __declspec(dllexport) const char* get_winapi() {
        static char buffer[4096];
        DWORD result = GetEnvironmentVariable("PATH_TEST", buffer, sizeof(buffer));
        if (result > 0 && result < sizeof(buffer)) {
            return buffer;
        }
        return nullptr;
    }
}
  • C#測(cè)試的源代碼:
using System;
using System.Runtime.InteropServices;

class Program
{
    static void Main(string[] args)
    {
        string pathVariable = Environment.GetEnvironmentVariable("PATH_TEST");
        pathVariable += @"C:\Your\New\Path**********";
        Environment.SetEnvironmentVariable("PATH_TEST", pathVariable);
        Console.WriteLine("C# PATH environment variable:");
        Console.WriteLine(Environment.GetEnvironmentVariable("PATH_TEST"));
        Console.WriteLine("C++ PATH environment variable:");
        Print();
    }
    [DllImport("TestC.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern IntPtr get();
    static void Print()
    {
        var s = get();
        string result = Marshal.PtrToStringAnsi(s);
        Console.WriteLine(result);
    }

}
  • C++代碼構(gòu)建的編譯代碼:
@echo off

if exist build (
    echo Build folder already exists. Deleting...
    rmdir /s /q build
)

echo Build folder create..
mkdir build

echo Running CMake configuration...
cmake -B build -DCMAKE_CXX_COMPILER=g++ -G Ninja

echo Building the project...
cmake --build build

echo Build completed.

三、解釋

實(shí)驗(yàn)表達(dá)了什么?

通過(guò)實(shí)驗(yàn)可以發(fā)現(xiàn),凡是Windows.h庫(kù)定義的【獲取環(huán)境變量】的函數(shù)方法,都可以正常獲得。只有標(biāo)準(zhǔn)庫(kù)下面的getenv是獲得不了的。

但需要注意的是,msvc定義的標(biāo)準(zhǔn)庫(kù)getenv是可以獲得的!

因此,可以明確【g++下的標(biāo)準(zhǔn)庫(kù)實(shí)現(xiàn)是可能存在問(wèn)題的】。

G++下的getenv為什么獲得不了環(huán)境變量?

我先去看了一下G++此處的源代碼:

/* glibc/stdlib/getenv.c下的代碼 */

#include <stdlib.h>
#include <string.h>
#include <unistd.h>

char *
getenv (const char *name)
{
  if (__environ == NULL || name[0] == '\0')
    return NULL;

  size_t len = strlen (name);
  for (char **ep = __environ; *ep != NULL; ++ep)
    {
      if (name[0] == (*ep)[0]
	  && strncmp (name, *ep, len) == 0 && (*ep)[len] == '=')
	return *ep + len + 1;
    }

  return NULL;
}
libc_hidden_def (getenv)

代碼可以看出,該環(huán)境變量的獲取本質(zhì)就是循環(huán)__environ這個(gè)字符指針數(shù)組來(lái)尋找對(duì)應(yīng)名稱(chēng)的環(huán)境變量。

在繼續(xù)搜索這個(gè)變量,發(fā)現(xiàn)其是在DLL 首次加載時(shí),CRT(注意是G++的編譯,而不是msvc) 會(huì)把「操作系統(tǒng)提供的環(huán)境變量,而不是進(jìn)程環(huán)境」復(fù)制到自己的內(nèi)存空間(CRT的角度是之后這部分環(huán)境數(shù)據(jù)就與系統(tǒng)環(huán)境“斷開(kāi)”了),從而完成該數(shù)組__environ的初始化,隨后的getenv就從該數(shù)組里拿。

由于SetEnvironmentVariable修改的是進(jìn)程環(huán)境的環(huán)境變量,因此其兩者根本就是在對(duì)兩個(gè)副本環(huán)境變量(因?yàn)楫吘故沁M(jìn)程級(jí),不能影響系統(tǒng),因此是副本)在操作,所以不互通!

_putenv()小插曲

在搜索問(wèn)題的過(guò)程中,發(fā)現(xiàn)有人說(shuō)_putenv()設(shè)定的誰(shuí)都可以獲得Environment.GetEnvironmentVariable()以及getenv()。實(shí)驗(yàn)了一下,竟然發(fā)現(xiàn)真的可以!

但仔細(xì)看了引入其函數(shù)的頭文件,果不其然是windows.h!

于是,為什么 C++ 標(biāo)準(zhǔn)庫(kù)中只有 getenv() 而沒(méi)有 setenv()?

  • 主要是因?yàn)楦鱾€(gè)操作系統(tǒng)對(duì)環(huán)境變量的實(shí)現(xiàn)和管理存在差異,因此,C++ 標(biāo)準(zhǔn)委員會(huì)在設(shè)計(jì)時(shí),避免引入一個(gè)難以在所有系統(tǒng)上實(shí)現(xiàn)一致行為的功能。
  • 在 POSIX 系統(tǒng)(如 Linux 和 macOS)上,通??梢允褂?setenv() 或 putenv() 來(lái)設(shè)置環(huán)境變量
  • 但在 Windows 上,管理環(huán)境變量的方式有所不同(如使用 SetEnvironmentVariable())。

四、啟發(fā)

如何在P/Invoke中使用【獲取和修改環(huán)境變量】

  • 在Win環(huán)境下,「獲取環(huán)境變量」還是避免使用getenv,統(tǒng)一使用windows.h下的庫(kù)函數(shù)如_putenv()、GetEnvironmentVariable函數(shù)?!冈O(shè)置環(huán)境變量」由于都是從windows.h庫(kù)中跑,其實(shí)無(wú)所謂用什么函數(shù)。
  • 在Unix環(huán)境下,正常使用setenv和getenv即可。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • C++數(shù)組的定義詳情

    C++數(shù)組的定義詳情

    這篇文章主要介紹了C++數(shù)組的定義詳情,上一篇文章我們學(xué)習(xí)了類(lèi)型,接下倆我們九在類(lèi)型的基礎(chǔ)上展開(kāi)本篇內(nèi)容數(shù)組的常用方法以及C++標(biāo)準(zhǔn)庫(kù)提供的一些關(guān)于數(shù)組的容器,需要的朋友可以參考一下,希望對(duì)你有所幫助
    2021-12-12
  • C++11右值引用和std::move語(yǔ)句實(shí)例解析(推薦)

    C++11右值引用和std::move語(yǔ)句實(shí)例解析(推薦)

    右值引用(及其支持的Move語(yǔ)意和完美轉(zhuǎn)發(fā))是C++0x將要加入的最重大語(yǔ)言特性之一。這篇文章主要介紹了C++11右值引用和std::move語(yǔ)句實(shí)例解析,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-03-03
  • ReSharper 的安裝使用詳細(xì)教程

    ReSharper 的安裝使用詳細(xì)教程

    resharper安裝教程是關(guān)于vs2012一個(gè)非常好用的插件的安裝教程,建議大家嘗試安裝,今天通過(guò)本教程幫助大家學(xué)習(xí)ReSharper 的安裝使用詳細(xì)教程,感興趣的朋友一起看看吧
    2021-06-06
  • C++實(shí)現(xiàn)路口交通燈模擬系統(tǒng)

    C++實(shí)現(xiàn)路口交通燈模擬系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)路口交通燈模擬系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Libevent的使用及reactor模型詳解

    Libevent的使用及reactor模型詳解

    Libevent?是一個(gè)用C語(yǔ)言編寫(xiě)的、輕量級(jí)的開(kāi)源高性能事件通知庫(kù),主要有以下幾個(gè)亮點(diǎn):事件驅(qū)動(dòng)(?event-driven),高性能;輕量級(jí),專(zhuān)注于網(wǎng)絡(luò),這篇文章主要介紹了Libevent的使用及reactor模型,需要的朋友可以參考下
    2024-03-03
  • 一文帶你深入了解Qt中的順序容器類(lèi)與關(guān)聯(lián)容器類(lèi)

    一文帶你深入了解Qt中的順序容器類(lèi)與關(guān)聯(lián)容器類(lèi)

    Qt中也有很多容器類(lèi),他們?cè)诖嫒∷俣?、?nèi)存開(kāi)銷(xiāo)等方面進(jìn)行了優(yōu)化,使用起來(lái)更輕量級(jí)、更便捷,下面就跟隨小編一起來(lái)學(xué)習(xí)一下它們的具體使用吧
    2024-04-04
  • C++實(shí)現(xiàn)文件逐行讀取與字符匹配的示例詳解

    C++實(shí)現(xiàn)文件逐行讀取與字符匹配的示例詳解

    這篇文章主要為大家詳細(xì)介紹了如何溧陽(yáng)C++實(shí)現(xiàn)文件逐行讀取與字符匹配的功能,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下
    2023-03-03
  • c語(yǔ)言中字符串函數(shù)(庫(kù)函數(shù)使用)和模擬實(shí)現(xiàn)圖文教程

    c語(yǔ)言中字符串函數(shù)(庫(kù)函數(shù)使用)和模擬實(shí)現(xiàn)圖文教程

    C語(yǔ)言中對(duì)字符和字符串的處理很是頻繁,但是C語(yǔ)言本身并沒(méi)有字符串類(lèi)型,這篇文章主要給大家介紹了關(guān)于c語(yǔ)言中字符串函數(shù)(庫(kù)函數(shù)使用)和模擬實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2024-01-01
  • C語(yǔ)言通過(guò)棧實(shí)現(xiàn)小人走迷宮

    C語(yǔ)言通過(guò)棧實(shí)現(xiàn)小人走迷宮

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言通過(guò)棧實(shí)現(xiàn)小人走迷宮,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C數(shù)據(jù)結(jié)構(gòu)之雙鏈表詳細(xì)示例分析

    C數(shù)據(jù)結(jié)構(gòu)之雙鏈表詳細(xì)示例分析

    以下是對(duì)c語(yǔ)言中的雙鏈表進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過(guò)來(lái)參考下
    2013-08-08

最新評(píng)論