为啥windows在调用函数时需要大小?
Posted
技术标签:
【中文标题】为啥windows在调用函数时需要大小?【英文标题】:Why does windows need the size when calling a function?为什么windows在调用函数时需要大小? 【发布时间】:2011-04-08 04:56:51 【问题描述】:我正在尝试学习一点 C++,但我有一个愚蠢的问题。考虑这段代码:
TCHAR tempPath[255];
GetTempPath(255, tempPath);
为什么 windows 需要 var tempPath 的大小?我看到 GetTempPath
被声明为:
GetTempPath(dword size, buf LPTSTR);
如果没有&
操作符,windows 如何改变 buf 值?功能不应该是这样吗?
GetTempPath(buf &LPTSTR);
谁能提供一个简单的GetTempPath
实现示例,以便我了解size
是如何使用的?
编辑:
感谢您的所有回答,它们都是正确的,我给了您所有 +1。但我的意思是“有人可以提供一个简单的GetTempPath
实现吗?我尝试编写一个类似于 windows 使用的函数,如下所示:
void MyGetTempPath(int size, char* buf)
buf = "C:\\test\\";
int main(int argc, char *argv[])
char* tempPath = new TCHAR[255];
GetTempPathA(255, tempPath);
MessageBoxA(0, tempPath, "test", MB_OK);
return EXIT_SUCCESS;
但它不起作用。 MessageBox 显示“##$”字符串。MyGetTempPath 应该如何编码才能正常工作?
【问题讨论】:
C++ 没有内置的字符串类型。相反,您使用字符数组和指针。语句buf = "C:\\test\\"
将“C:\\test\\”的地址复制到buff。但是,由于指针本身是按值传递的,所以调用者的 buf 没有更新,它什么也不做。尝试改用strcpy_s
。
【参考方案1】:
Windows 需要大小作为安全预防措施。如果将字符复制到缓冲区末尾,它可能会使应用程序崩溃。当您提供长度时,它可以防止这种情况发生。
数组变量像指针一样工作。它们指向数组中的数据。所以不需要&
操作符。
不确定您要查找的示例类型。就像我说的,它只需要验证它没有写出超出空间的字符。
【讨论】:
不需要&
,因为存在从数组到指向数组第一个元素的指针的隐式转换,而不是因为它是指向第一个元素的指针元素。实际上,使用&
会产生指向数组类型的指针,例如int(*)[255]
。
@GMan:您能否澄清“像指针一样工作”和“从数组隐式转换为指向第一个元素的指针”之间的区别?我可以向你保证,我确切地知道它是如何工作的。你在争论语义吗?
@Johathan:首先,因为数组实际上并不指向任何东西,它只是包含数据。其次,在某些情况下不会发生从“数组名”到“指向数组开头的指针”的转换,例如sizeof(array)
。同样重要的是不要在 extern
声明中混淆两者:extern int a[];
和 extern int *a;
不相同。
@Jonathan:嗯,我们可能在争论语义,但我会说我的语义是正确的。 :) 数组不是指针,也不像指针那样工作。但是,在某些情况下,它们可能会转换为它们。 (如果您认为这意味着数组像指针一样工作,那么流像布尔值一样工作,整数像浮点数一样工作。)
当将数组作为参数传递时(通过指定数组名),传递数组中第一项的地址。如果我有一个指向数组的指针并将指针作为参数传递,那么 also 将传递数组中第一项的地址。所以在关于传递参数的讨论中,我说数组可以像指针一样工作。【参考方案2】:
数组不能按值传递给函数。相反,它被转换为指向第一个元素的指针,然后传递给函数。拥有指向数据的(非常量)指针允许修改:
void foo(int* i)
if (i) (don't dereference null)
*i = 5; // dereference pointer, modify int
同样,该函数现在有一个指向它可以写入的TCHAR
的指针。然后,它需要大小,因此它确切地知道在初始值之后存在多少TCHAR
。否则它不知道数组有多大。
【讨论】:
【参考方案3】:GetTempPath() 输出到您的“tempPath”字符数组中。如果你不告诉它在数组中分配了多少空间(255),它就无法知道它是否有足够的空间将路径字符串写入 tempPath。
C/C++ 中的字符数组几乎只是指向内存中位置的指针。它们不包含有关自身的其他信息,例如 C++ 或 Java 类的实例。我认为,Windows API 的肉和土豆是在 C++ 真正没有太多惯性之前设计的,因此您经常不得不使用较旧的 C 风格技术和内置数据类型来使用它。
【讨论】:
【参考方案4】:如果你想避免尺寸,可以尝试以下包装:
template<typename CHAR_TYPE, unsigned int SIZE>
void MyGetTempPath (CHAR_TYPE (&array)[SIZE]) // 'return' value can be your choice
GetTempPath(SIZE, array);
现在你可以像下面这样使用:
TCHAR tempPath[255];
MyGetTempPath(tempPath); // No need to pass size, it will count automatically
在您的另一个问题中,为什么我们不使用以下内容:
GetTempPath(buf &LPTSTR);
是因为,当您想通过引用(而不是地址)传递数据类型时使用&
。我不知道buf
的类型转换为什么,但它应该是某种指针类型。
【讨论】:
【参考方案5】:谁能提供一个简单的 GetTempPath 实现示例所以我 可以看看size是怎么用的吗?
第一种方式(基于 MAX_PATH 常量):
TCHAR szPath[MAX_PATH];
GetTempPath(MAX_PATH, szPath);
第二种方式(基于GetTempPath描述):
DWORD size;
LPTSTR lpszPath;
size = GetTempPath(0, NULL);
lpszPath = new TCHAR[size];
GetTempPath(size, lpszPath);
/* some code here */
delete[] lpszPath;
不需要windows如何在没有&操作符的情况下改变buf值?
& 运算符,因为数组名称是指向第一个数组元素(或所有数组)的指针。尝试下一个代码来证明这一点:
TCHAR sz[1];
if ((void*)sz == (void*)&sz) _tprintf(TEXT("sz equals to &sz \n"));
if ((void*)sz == (void*)&(sz[0])) _tprintf(TEXT("sz equals to &(sz[0]) \n"));
【讨论】:
【参考方案6】:根据要求,一个非常简单的实现。
bool MyGetTempPath(size_t size, char* buf)
const char* path = "C:\\test\\";
size_t len = strlen(path);
if(buf == NULL)
return false;
if(size < len + 1)
return false;
strncpy(buf, path, size);
return true;
对新函数的调用示例:
char buffer[256];
bool success = MyGetTempPath(256, buffer);
【讨论】:
【参考方案7】:来自http://msdn.microsoft.com/en-us/library/aa364992(v=vs.85).aspx
DWORD WINAPI GetTempPath(
__in DWORD nBufferLength,
__out LPTSTR lpBuffer
);
所以 GetTempPath 的定义类似于
GetTempPath(DWORD nBufferLength, LPTSTR& lpBuffer);
什么意思,编译器通过引用传递值 lpBuffer。
【讨论】:
Windows API 是纯 C,C 中没有引用类型。__out
只是对 (Microsoft) 编译器的提示,根本不会更改参数类型。
以上是关于为啥windows在调用函数时需要大小?的主要内容,如果未能解决你的问题,请参考以下文章
c#里为啥有的使用时函数需要new一个对象而有的不用?为啥不直接调用就好?