【发布时间】:2010-11-09 03:11:43
【问题描述】:
(这与其说是学究气的练习,倒不如说是个问题。)
我已经制作了一个不错的小程序,它是我的 linux 操作系统的原生程序,但我认为它也足以存在于我的 Windows 机器上。因此,我想访问 Windows 的环境变量,MSDN 引用了这样一个示例:
const DWORD buff_size = 50;
LPTSTR buff = new TCHAR[buff_size];
const DWORD var_size = GetEnvironmentVariable("HOME",buff,buff_size);
if (var_size==0) { /* fine, some failure or no HOME */ }
else if (var_size>buff_size) {
// OK, so 50 isn't big enough.
if (buff) delete [] buff;
buff = new TCHAR[var_size];
const DWORD new_size = GetEnvironmentVariable("HOME",buff,var_size);
if (new_size==0 || new_size>var_size) { /* *Sigh* */ }
else { /* great, we're done */ }
}
else { /* in one go! */ }
这(对我而言)不如使用 getenv 并仅检查空指针那么好。我也不想动态分配内存,因为我只是想让程序在 Windows 和我的 linux 操作系统上运行,这意味着这个 MS 代码必须与 nix 代码很好地配合。更具体地说:
template <class T> // let the compiler sort out between char* and TCHAR*
inline bool get_home(T& val) { // return true if OK, false otherwise
#if defined (__linux) || (__unix)
val = getenv("HOME");
if (val) return true;
else return false;
#elif defined (WINDOWS) || defined (_WIN32) || defined (WIN32)
// something like the MS Code above
#else
// probably I'll just return false here.
#endif
}
所以,我必须在堆上进行普遍分配,或者在调用函数中使用#ifdef 来释放内存。不是很漂亮。
当然,我本来可以一开始就在堆栈上分配“buff”,但是如果在第一次调用 GetEnvironmentVariable 时“buff_size”不够大,我就必须创建一个新的TCHAR[]。更好,但是如果我是一个书呆子并且不想到处创建多余的数组怎么办?有什么更美观的想法吗?
我不是很了解,所以有人会嫉妒我故意强迫 GetEnvironmentVariable 失败以获取字符串大小吗?有没有人看到以下问题:
const DWORD buff_size = GetEnvironmentVariable("HOME",0,0);
TCHAR buff[buff_size];
const DWORD ret = GetEnvironmentVariable("HOME",buff,buff_size);
// ...
还有其他想法或建议吗? (或者更正明显的错误?)
更新:
下面有很多有用的信息。我认为最好的办法是使用static char[],例如:
inline const char* get_home(void) { // inline not required, but what the hell.
#if defined (__linux) || (__unix)
return getenv("HOME");
#elif defined (WINDOWS) || defined (WIN32) || defined (_WIN32)
static char buff[MAX_PATH];
const DWORD ret = GetEnvironmentVariableA("USERPROFILE",buff,MAX_PATH);
if (ret==0 || ret>MAX_PATH)
return 0;
else
return buff;
#else
return 0;
#endif
}
也许这不是最优雅的方式,但它可能是在 *nix 和 Windows 之间同步我想做的最简单的方式。 (稍后我还会担心 Unicode 支持。)
感谢所有帮助过的人。
【问题讨论】:
-
在 C++ 中,您应该将值作为
std::basic_string<TCHAR>返回。这解决了内存管理问题。但是,请注意%HOME%默认没有设置。您可能正在寻找%USERPROFILE%、`%APPDATA%` 或%LOCALAPPDATA%。 -
我对windows环境变量不熟悉,所以默认我知道的!是的,
%USERPROFILE%是我需要的。返回字符串值听起来是个好主意!我可以只返回一个空字符串作为失败指示器。当我懒得放下笔记本电脑时,我会试一试…… -
十多年后,我也感受到了同样的痛苦:(冒着被贴上书呆子标签的巨大风险(我会为此获得一个链接徽章吗?),我认为你的支票应该被收回 > = MAX_PATH 正如 API 文档所说:“如果 lpBuffer 不足以容纳数据,则返回值是缓冲区大小,以字符为单位,需要容纳字符串及其终止空字符和 lpBuffer 的内容是未定义的。” ,因此 MAX_PATH 长度将是一个错误。我认为。对不起!我认为在调用之间也存在值变化的理论风险,这可能意味着您的第二次调用可能会失败。
-
@MarkH 啊,是的,谢谢。是的,应该考虑潜在的竞争条件。敢说自从我第一次问这个问题以来事情已经发生了很大的变化,也许 Windows API 现在对我的问题有一个非常不同的规范答案?我不能说,但谢谢你的两点(和同情!)。
标签: c++ visual-c++