为啥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);

是因为,当您想通过引用(而不是地址)传递数据类型时使用&amp;。我不知道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语言----为啥函数定义时不用加;

为啥这个递归函数超过调用堆栈大小?

c#里为啥有的使用时函数需要new一个对象而有的不用?为啥不直接调用就好?

调用函数时为啥形参的值不能传给实参

为啥在尝试调用采用动态参数的基本构造函数/方法时会出现此编译错误?

为啥这个 stl 函数调用会导致不正确的布尔评估? [复制]