【问题标题】:Why does sizeof(argv)/sizeof(argv[0]) give me the size of an array in C++?为什么 sizeof(argv)/sizeof(argv[0]) 给我 C++ 中数组的大小?
【发布时间】:2013-05-15 00:16:06
【问题描述】:

如果我在 main 中有一个数组作为参数

int main(int argc, char* argv[])

为什么会

sizeof(argv)/sizeof(argv[0])

总是可靠地给我数组的长度?

【问题讨论】:

  • 也许这是数组的大小(以字节为单位)或数组除以数组元素的大小(以字节为单位),等于元素的数量。我只是猜测——我不是 C++ 人。
  • 如果长度为 1,它只会“可靠”地给你长度。你的两个 sizeof 参数都是指针。
  • int main(int argc, *char argv[]) 应该是 int main(int argc, char* argv[])

标签: c++ arrays pointers sizeof


【解决方案1】:

没有。

写这个答案的时候我可能有点忘乎所以;对于一个相当简单的问题,这太过分了语言律师的方法。我将添加这个足以回答问题的快速摘要。答案的迂腐和过于冗长的版本低于水平线。

给定:

int main(int argc, char* argv[])

argv 根本不是数组;这是一个指针。 (C 和 C++ 不允许数组类型的参数;看起来像数组参数的东西实际上是指针参数。)argv 确实(在运行时)指向数组的第一个元素,但没有信息 在声明中关于该数组有多大。这就是为什么我们需要argc 参数来提供该信息。

所以sizeof(argv)/sizeof(argv[0]) 没有给你数组中元素的数量;它只是将指针的大小除以指针的大小,可能给你1。 (为什么只“可能”?这是下面过于迂腐的答案的一部分。)

现在,如果您将某些东西明确定义为数组对象:

int an_array[42];

可以使用该习语来计算数组中元素的数量:

sizeof an_array / sizeof an_array[0]

这会产生42,即数组中的元素数。它的工作方式(我认为)相当简单:它是整个数组的大小(以字节为单位)除以其中一个元素的大小(以字节为单位)。

但它适用于实际数组,不适用于像argv 这样看起来像数组但实际上是指针的东西。

数组和指针之间的关系可能会令人困惑。 comp.lang.c FAQ 的第 6 节解释得很好,大部分或全部适用于 C 和 C++。

现在是冗长的迂腐解释,题外话太多:


argv 是一个指针,特别是指向char 的指针。作为参数声明(在该上下文中),char *argv[] 等效于 char **argv

sizeof (argv)char** 指针中的字节数。

sizeof (argv[0])char* 指针中的字节数。

sizeof (argv) / sizeof (argv[0]) 很可能为 1(假设 char*char** 具有相同的大小,它们在大多数实现中都是如此)。

现在对于被定义为数组对象的东西:

some_type an_array[COUNT];

该表达式确实有效;这个:

sizeof an_array / sizeof an_array[0]

确实为您提供an_array 中的元素数量,即COUNT。我认为,其原因应该是相当明显的。数组中的字节数是数组的一个元素中的字节数乘以元素数。所以:

sizeof an_array == sizeof an_array[0] * COUNT

并且,重新排列术语:

sizeof an_array / sizeof an_array[0] == COUNT

顺便说一下,sizeof an_array[0] 也可以写成sizeof *an_array,这是由于索引运算符在 C 中的定义方式。

(请注意,sizeof 运算符不需要在其参数周围使用括号,如果该参数是诸如对象名称之类的表达式。sizeof 的操作数是表达式或带括号的类型名称。但如果你喜欢总是在sizeof 中使用括号,你可以这样做。)

这是计算数组中元素数量的常用习语——但它仅在您拥有数组本身的名称而不是指向其第一个元素的指针时才有效。

[以下适用于 C。我相信它也适用于 C++(我最初没有注意到问题被标记为 C++,而不是 C)。]

在回答 cmets 中提出的问题时,不,char*char** 不需要具有相同的大小。 C标准对指针表示的要求是:

指向 void 的指针应具有相同的表示和对齐方式 要求作为指向字符类型的指针。同样,指针 兼容类型的合格或不合格版本应具有 相同的表示和对齐要求。所有指向的指针 结构类型应具有相同的表示和对齐方式 互相要求。所有指向联合类型的指针都应具有 相同的表示和对齐要求。指针 到其他类型不需要具有相同的表示或对齐方式 要求。

参考:N1570,6.2.5p28。

C++ 标准至少有一些这样的内容; N3485 草案的第 3.9.2 [basic.compound] 节说:

cv void* 类型的对象应具有相同的表示和对齐方式 要求为 cv char*.

我还没有找到我从 C 标准中引用的其余内容的相应文本。

在字寻址的机器上,char* 指针可能需要比char** 指针所需的更多信息来指定字和该字中的字节,而char** 指针只需要指定对齐的字。

【讨论】:

  • 不是要求它们的尺寸相同吗?我认为唯一可以不同的指针是函数指针,或者成员函数指针。
  • 他们必须拥有相同的大小,不是吗?否则(char*)(char**)(char*)p 可能会丢失信息...
  • 计算数组元素个数的新常用习语应该std::array<T, N>::size() :)
  • @Mehrdad:可以。 C++ 标准不要求您的表达式具有任何有意义的结果,或表示兼容(例如:实现可能对 char** 值强制执行 4 字节对齐,并且对 char* 强制执行 1 字节对齐并且可以违反这些时的段错误)。唯一的要求是void* 对它们都进行了统治,因此您可以将任何指针值塞入其中并完好无损地取回。
  • @Mehrdad:不,它们不必具有相同的大小。如果char* 有对齐限制,则允许您列出的表达式丢失信息。 OTOH char** p; (char**)(char*)p 不能丢失信息,因为 char 从来没有对齐限制。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-21
  • 2017-03-12
  • 2012-08-27
  • 2015-08-21
  • 2013-09-24
  • 2019-03-12
相关资源
最近更新 更多