在 C 中将 sizeof() 与指向结构的指针一起使用

Using sizeof() with pointer to struct in C

我现在正在学习 C,在尝试我的 uni 课程中的一些代码片段时遇到了一个小问题。

这是关于指向结构的 typedef 指针及其在 sizeof() 函数中的用法。

#include <stdio.h>
#include <stdlib.h>

// Define struct
struct IntArrayStruct
{
  int length;
  int *array;
};
// Set typedef for pointer to struct
typedef struct IntArrayStruct *IntArrayRef;

// Declare function makeArray()
IntArrayRef makeArray(int length);

// Main function
int main(void)
{
  // Use makeArray() to create a new array
  int arraySize = 30;
  IntArrayRef newArray = makeArray(arraySize);
}

// Define makeArray() with function body
IntArrayRef makeArray(int length)
{
  IntArrayRef newArray = malloc(sizeof(*IntArrayRef)); // ERROR
  newArray->length = length;
  newArray->array = malloc(length * sizeof(int));
  return newArray;
}

并且 代码在 class 中使用的 IDE 中确实有效 (Virtual C),但是当我尝试完全相同的示例时在 VSCode 中使用 GNU Make 或 GCC 编译它,它 returns 一个错误,因为 malloc() 函数调用中的 sizeof(*IntArrayRef) 被标记为一个意外的类型名称。

error: unexpected type name 'IntArrayRef': expected expression

然而,当我将其更改为 sizeof(IntArrayStruct) 时,一切正常。

*IntArrayRefIntArrayStruct 的值不一样吗?

IntArrayRef 是类型的名称,因此 *IntArrayRef 是无效语法。您可以(并且应该)做的是给出变量的名称并取消引用:

IntArrayRef newArray = malloc(sizeof(*newArray)); 

以下是您的类型名称之间的相互关系:

struct IntArrayStruct *  == IntArrayRef

因此,newArray 的类型 IntArrayRefstruct IntArrayStruct *

相同

因此,如果您想要 pointer 类型的大小,您可以使用

之一
sizeof (IntArrayRef)
sizeof (struct IntArrayStruct *)
sizeof newArray

如果您想要指向类型(实际结构类型)的大小,您可以使用

之一
sizeof (struct IntArrayStruct)
sizeof *newArray

sizeof 是一个运算符,而不是一个函数 - 仅当操作数是类型名称(包括 typedef 名称)时才需要括号。在像 sizeof (*newArray) 这样的非类型操作数周围使用括号 没有什么坏处 ,但它们不是必需的。

作为风格说明,将指针类型隐藏在 typedef 后面通常不是一个好主意,尤其是当该类型的用户必须知道它是指针类型才能正确使用它时。 IOW,如果该类型的用户必须取消引用某些内容,那么该内容的指针应该是明确的。即使用户 不需要 需要显式取消引用它,你仍然不应该隐藏类型的指针(将标准库中的 FILE * 类型作为举个例子——你从来没有真正取消引用一个 FILE * 对象,但它的指针仍然是明确的)。

否则,请准备好编写一个完整的 API 对用户隐藏所有指针操作。

比较

sizeof(IntArrayStruct*)
sizeof(IntArrayRef)

sizeof(IntArrayStruct)

前两个是一样的,都是指针的大小。 IE。与 sizeof(int*)、sizeof(long*)、sizeof(void*) 等相同

第三个是实际数据结构的大小。如果您使用 malloc 为它创建 space,这就是您想要的。


此外,指针和引用在 C++ 中是两种不同的东西,因此使用缩写“ptr”来传达指针这一事实可能不会造成混淆。

最后,如前所述,创建新类型名称只是为了表示指向结构类型的指针,这是非标准的。这会混淆其他人而没有太大好处。