【问题标题】: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

标签: c++ winapi


【解决方案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) 编译器的提示,根本不会更改参数类型。
            猜你喜欢
            • 2020-08-22
            • 1970-01-01
            • 2012-07-20
            • 2018-01-03
            • 2012-10-07
            • 2014-11-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多