【问题标题】:Using sizeof() with pointer to struct in C在 C 中使用 sizeof() 和指向结构的指针
【发布时间】:2021-03-28 10:41:25
【问题描述】:

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

这是关于指向结构的 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;
}

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

error: unexpected type name 'IntArrayRef': expected expression

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

*IntArrayRefIntArrayStruct 的值不一样吗?

【问题讨论】:

  • 使用sizeof(*newArray)
  • 顺便说一句,通常认为 typedef 指针的风格很差。见stackoverflow.com/questions/750178/…
  • sizeof 不是函数,而是运算符。代替sizeof(*newArray),使用sizeof *newArray
  • sizeof(IntArrayStruct) 在 C 中无效,因为 IntArrayStruct 是一个标签,而不是一个类型,并且没有意义,除非它前面有 structunionenum,或者有是具有该名称的变量或 typedef。 (也许您将其编译为 C++?)。
  • @WilliamPursell 那么sizeof *newArray * 4 的结果是什么?是否与sizeof ( *newArray * 4 )( sizeof *newArray ) * 4 相同负责三年后代码维护的新聘开发人员知道吗? sizeof( *newArray )明确sizeof *newArray 不是。

标签: c struct malloc pass-by-reference sizeof


【解决方案1】:

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

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

【讨论】:

  • 更好的是:IntArrayRef newarray = malloc(sizeof *newArray);
【解决方案2】:

您的类型名称之间的关系如下:

struct IntArrayStruct *  == IntArrayRef

因此,newArray 的类型为 IntArrayRef,与 struct IntArrayStruct * 相同

所以,如果你想要 pointer 类型的大小,你可以使用

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

如果你想要 pointed-to 类型(实际的结构类型)的大小,你可以使用其中之一

sizeof (struct IntArrayStruct)
sizeof *newArray

sizeof 是运算符,而不是函数 - 仅当操作数是类型名称(包括 typedef 名称)时才需要括号。在sizeof (*newArray) 等非类型操作数周围使用括号伤害,但它们不是必需的。

作为一种风格说明,将指针类型隐藏在 typedef 后面通常不是一个好主意,特别是如果该类型的用户必须知道它是一个指针类型才能正确使用它。 IOW,如果该类型的用户必须取消引用某些东西,那么该东西的指针应该是明确的。即使用户不需要需要显式取消引用它,你仍然不应该隐藏类型的指针(以标准库中的 FILE * 类型为例 - 你永远不会实际上取消引用 FILE * 对象,但它的指针仍然是明确的)。

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

【讨论】:

  • 感谢您的深刻回答!我将其更改为sizeof(*newArray),因为这正是我想要的。但是,我仍然想知道 - 为什么这个其他 IDE VisualC 与 sizeof(*IntArrayRef) 一起工作,如果它应该只是一个语法错误?
  • @lbeul:好问题。我不知道答案。 MSVC 总是有一些问题,但我真的很惊讶编译的代码。
【解决方案3】:

比较

sizeof(IntArrayStruct*)
sizeof(IntArrayRef)

sizeof(IntArrayStruct)

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

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


此外,指针和引用在 C++ 中是两个不同的东西,因此用缩写“ptr”来传达某些东西是指针这一事实可能不会让人感到困惑。

最后,如前所述,创建一个新的类型名称,只是为了表示一个指向结构类型的指针,是非标准的。这会使其他人感到困惑而没有太多好处。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-21
    • 2021-07-14
    • 2010-09-25
    • 1970-01-01
    • 2012-07-16
    • 1970-01-01
    • 2016-08-25
    • 1970-01-01
    相关资源
    最近更新 更多