C:为啥 size_t 不是 C 关键字?

Posted

技术标签:

【中文标题】C:为啥 size_t 不是 C 关键字?【英文标题】:C: Why isn't size_t a C keyword?C:为什么 size_t 不是 C 关键字? 【发布时间】:2010-10-18 21:23:36 【问题描述】:

sizeof 是一个 C 关键字。它以名为size_t 的类型返回大小。但是,size_t不是关键字,而是主要在 stddef.h 和其他 C 标准头文件中定义。

假设您要创建一个包含任何 C 标准头文件或库的 C 程序。 (例如,如果您正在创建 OS 内核。)现在,在这样的代码中,可以使用 sizeof(它是 C 关键字,因此它是 语言 的一部分),但它返回的类型 (size_t) 不可用!

这不是表示 C 标准规范中存在某种问题吗?你能澄清一下吗?

【问题讨论】:

许多头文件是完全安全和明智的,即使在操作系统内核中也是如此。您在内核中担心的问题是链接到库,不包括标头。 RBerteig:为了论证,假设我想创建一个只使用该语言的 C 程序,没有头文件/库,并且我想使用 sizeof。 您很可能需要在汇编中编写自己的实现库。如果没有标头和库(以及它们的相关函数),您将无法做很多事情。 标准标题是语言的一部分。许多确实定义了标准库的接口,并且有充分的理由不在内核或深度嵌入式系统中使用这些接口。但其他人主要定义与实现相关的有用内容:stddef.h、limits.h 是示例。 Chris 和 RBerteig:是的,但是让我们考虑一个不使用任何头文件/库的程序,只是做一些算术运算。 【参考方案1】:

C 标准中的一些标头是为 独立 环境定义的,即适合使用,例如在操作系统内核中。它们不定义任何函数,仅定义和 typedef。

它们是 float.h、iso646.h、limits.h、stdarg.h、stdbool.h、stddef.h 和 stdint.h。

在操作系统上工作时,从 这些 标头开始并不是一个坏主意。让它们可用会使你的内核中的许多事情变得更容易。尤其是 stdint.h 会变得很方便(uint32_t 等)。

【讨论】:

DevSolar:OS 内核只是一个示例,而是考虑我想使用 sizeof 编写 C 程序但不包括任何 C 标头的情况。感谢您提供有关独立环境标头的信息,我不知道这一点。【参考方案2】:

我认为size_t不是关键字的主要原因是:

没有令人信服的理由。 C 和 C++ 语言的设计者一直倾向于在可能且合理的情况下在库中实现语言功能 向语言添加关键字可能会给现有的遗留代码体带来问题。这是他们通常不愿添加新关键字的另一个原因。

例如,在讨论 C++ 标准的下一个主要修订版时,Stroustrup had this to say:

C++0x 的改进应该以这样一种方式进行,即生成的语言更易于学习和使用。委员会的经验法则包括:

...

首选标准库工具而不是语言扩展

...

【讨论】:

不过,内置运算符sizeof 生成库类型size_t 的表达式感觉很奇怪。 :) @musiphil:把它想象成这样可能感觉不那么奇怪:库必须将 size_t 定义为 sizeof 运算符产生的类型。【参考方案3】:

这不是表示 C 标准规范中存在某种问题吗?

查看托管的 C 实现和独立的 C 实现之间的区别。独立式 (C99) 实现需要提供标头:

<float.h> <iso646.h> <limits.h> <stdarg.h> <stdbool.h> <stddef.h> <stdint.h>

这些头文件根本没有定义任何函数。它们定义了语言的某些特定于编译器的部分(例如,<stddef.h> 中的 offsetof 宏,以及 <stdarg.h> 中的变量参数列表宏和类型),但它们可以在没有实际构建到语言作为完整的关键字。

这意味着即使在您假设的内核中,您也应该期望 C 编译器提供这些头文件和任何底层支持函数 - 即使您提供其他所有内容。

【讨论】:

【参考方案4】:

原因很简单,因为它不是基本类型。如果您查看 C 标准,您会发现基本类型包括 intchar 等,但不包括 size_t。为什么这样?正如其他人已经指出的那样,size_t 是一种特定于实现的类型(即能够保持任何对象的“C 字节”数大小的类型)。

另一方面,sizeof 是一个(一元)运算符。所有运算符都是关键字。

【讨论】:

哪种基本类型不是特定于实现的? size_t 是特定于实现的类型不能成为它是库类型的原因。【参考方案5】:

它实际上并没有返回 size_t 类型的值,因为 size_t 本身不是具体类型,而是未指定的内置类型的 typedef。 Typedef 标识符(例如 size_t)完全等同于它们各自的底层类型(并在编译时转换为)。如果 size_t 在您的平台上定义为 unsigned int,则 sizeof 在您的系统上编译时返回一个 unsigned int。 size_t 只是维护可移植性的一种便捷方式,如果您明确地按名称使用它,则只需将其包含在 stddef.h 中。

【讨论】:

+1,正确答案。任何返回 typedef 的东西都不能真正说返回该 typedef。它返回 typedef 归结为的任何内容。如果您想要可移植性,请包含 stddef.h。如果不这样做,请在您的平台上查找 size_t 的定义并直接使用该类型。 Volte:我现在看到图片了。因此,编译器无法“看到”size_t,但使用的 sizeof 类型与编译器附带的头文件中 size_t 的 typedef 完全相同。 正如我在回答中指出的那样,编译器在编译时确实“看到”了 size)t 的 typedef - 从某种意义上说,它“知道” size_t Neil Butterworth:我无法在你的回复中理解它,但是当我阅读 Volte 的回复时理解了它:-) 现在让事情复杂一点,交叉编译器的本地和目的地会发生什么平台需要不同的 size_t? ;-) 编译器看到的 size_t 充其量只是一个实现细节,因为符合标准的 C 编译器可以用任何语言编写。 sizeof 的返回类型与 size_t 等价是一个标准问题,但实际的底层类型留给编译器的实现。【参考方案6】:

没有理由不包含 stddef.h,即使您正在使用内核 - 它为您的特定编译器定义了任何代码都需要的类型大小。

还请注意,几乎所有 C 编译器都是自编译的。因此, sizeof 运算符的实际编译器代码将使用 size_t 并引用与用户代码相同的 stddef.h 文件。

【讨论】:

Neil:但为了论证,假设我想创建一个不使用任何 C 标准头文件或库的程序。只是一个纯 C 语言程序。 头文件是C语言的part Neil Butterworth:我无法在你的回复中理解它,但是当我阅读 Volte 的回复时理解了它:-) 现在让事情复杂一点,交叉编译器的本地和目的地会发生什么平台需要不同的 size_t? ;-)【参考方案7】:

size_t 不是必须的关键字。不同的架构通常对整数类型有不同的大小。例如,如果 64 位机器没有决定将 int 设为 64 位数据类型,则可能会将 unsigned long long 作为 size_t .

如果你将 sizeof 设置为编译器的内置类型,那么它将剥夺进行交叉编译的能力。

另外,sizeof 更像是一个神奇的编译时宏(想想 c++ 模板),它解释了为什么它是关键字而不是定义的类型。

【讨论】:

这个论点没有实际意义,因为即使是整数类型的大小(例如)也会根据平台而变化。一个 int 可以是 4 个字节或 8 个字节等等,但 int 仍然是一个关键字。【参考方案8】:

size_t 实际上是一种类型——通常是无符号整数。 Sizeof 是一个给出类型大小的运算符。 sizeof 返回的类型实际上是特定于实现的,而不是 C 标准。它只是一个整数。

编辑: 要非常清楚,您不需要 size_t 类型才能使用 sizeof。我认为您正在寻找的答案是 - 是的,它是不一致的。但是,没关系。您实际上仍然可以正确使用 sizeof,而无需从头文件中定义 size_t。

【讨论】:

安东尼:我知道这一点。但是, size_t 是在 C 头文件中定义的,它不是语言的一部分。这就是断开连接的地方。 至少在 c++ 标准中(我没有 C 标准) sizeof 被定义为返回 size_t 而不仅仅是一个整数类型,并且该子句显式引用了 stddef.h Ash:以下代码有效: int main() double a;无符号整数 b = sizeof(a); 没有任何标题,这仍然是正确的。 size_t 的最小公分母是它是无符号整数类型。 size_t 基本上只是一个 typedef。 Anthony Kanago:这也可能意味着您使用的编译器知道 size_t。如果我们变得迂腐,这可能不是一个有效的案例,因为标准没有说编译器应该知道 size_t。【参考方案9】:

sizeof 是一个关键字,因为尽管它有名称和用法,但它是一个运算符,例如+=<,而不是一个函数 喜欢printf()atoi()fgets()。很多人忘记(或者只是不知道)sizeof 实际上是一个运算符,并且总是在编译时而不是在运行时解析。

C 语言不需要size_t 成为可用的、一致的语言。这只是标准库的一部分。 C 语言需要所有运算符。如果 C 使用关键字 plus 代替 + 来添加数字,则可以将其设为运算符。

此外,我一直在将 size_ts 半隐式重铸为 unsigned ints(以及常规的 ints,但 Kernighan 和 Ritchie 总有一天会为此而责备我)。如果愿意,您可以将 sizeof 的返回类型分配给 int,但在我的工作中,我通常只是将其直接传递给 malloc() 或其他东西。

【讨论】:

克里斯:谢谢你中肯的解释。但是,这并不意味着 size_t 就在 C 内部,就像 int/char 一样。那为什么要在标题中定义呢? 并不是说它被广泛使用(甚至被支持),但是对于 C99 风格的可变长度数组,sizeof 是在运行时评估的。 @Michael - 认真的吗?该死。但是,C99 的支持真的很差,所以我坚持使用 malloc() 和 realloc() 和 free() 来完成这项工作一段时间。 Michael Burr:这对我来说是个新闻!感谢您指出:-) @ChrisLutz 从什么时候开始对 C99 的支持不佳?这对我来说是新闻。并不是因为 MSVC 未能实施一个已有十多年历史的标准,该标准的支持很差……【参考方案10】:

来自MSDN:

当使用 sizeof 运算符时 对于 char 类型的对象,它产生 1

即使您没有可用/包含的 stddef.h 并且不知道 size_t,使用 sizeof 也可以获取对象相对于 char 的大小。

【讨论】:

但是如果你想在某个地方存储那个大小而不冒溢出的风险,你将需要 size_t 的 typedef。 schnaader:只是说 size_t 将是某种整数类型,但不完全是什么类型。 @Neil - 老实说,您多久会找到一个 sizeof() 返回甚至会溢出无符号字符的类型的类型?在我的系统上,即使是 FILE 结构也只有 88 个字节。

以上是关于C:为啥 size_t 不是 C 关键字?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在C语言中,“scanf”竟然可以作为自定义函数的函数名而不报错??

C语言关键字 _Bool 前面有个横杠不说,b还是个大写,为啥不直接bool,为啥这么折磨人?

C# 中的“var”是不是类似于 C 中的“size_t”?

为啥我的keil写C语言,关键字不变色

为啥 C++1* 仍然需要模板关键字来代替 Full Duck Typing

无法将参数 5 从 'SIZE_T *' 转换为 'size_t *' -- 为啥?