【问题标题】:C data type sizes intmax_t vs any other integer, void * vs any other pointerC 数据类型大小 intmax_t 与任何其他整数、void * 与任何其他指针
【发布时间】:2021-08-12 18:56:33
【问题描述】:

这是真的吗:

  • 没有数据指针大于sizeof(void *)?
  • 没有数据指针大于sizeof(char *)?
  • 没有大于sizeof(intmax_t)的整数?
  • floatdouble 都不大于sizeof(long double)

我知道intmax_t 可以存储任何其他有符号整数可以存储的任何值,但是是否要求大小也是任何整数的最大大小?或者是否有可能某个其他整数使用了比intmax_t 更多的填充位,以至于该整数的大小变得大于intmax_t,即使这个整数不能保存intmax_t 不能保存的任何值?

与指针类似,我知道任何其他数据指针都可以通过转换为 char *void * 并再次返回而不会丢失信息,但这是否意味着 char *void * 的大小必须是所有数据指针的最大可能大小?

我问这个问题是因为我在库中有一个函数,可以将字符串转换为由整数表示的不同类型。为了测试是否可以为给定的字符串完成此对话(格式正确),存在一个针对不同数据类型测试此对话的函数,该函数应为所有可能的类型保留足够的内存,进行对话,检查错误并释放又是这段记忆。是否足以确保intmax_t 足以覆盖所有整数类型?

【问题讨论】:

  • C 标准不需要这些。例如,一个实现可以包含带有int * 的元数据,而它不带有void *,使得int * 大于void *,即使它不能处理尽可能多的不同位置。或者它可以说把你搞砸,然后用一百个未使用的字节填充float。或者,void * 可能只有 8 个字节来访问任何 64 位地址,但所有函数指针都是 16 个字节,因为它们包含一些安全信息。
  • @EricPostpischil 对于函数指针:C 中没有要求void * 可以保存函数指针,事实上在一些哈佛架构的微控制器上,函数指针大于void *。其余的:这属于答案。
  • 简短的非技术版本是指针即指针即指针(任何给定实现只有一种大小)。 stdint.h 类型 intmax_t 可以保存任何有符号整数值,并且不考虑奇数 12 位浮点数或大于 double 的精度等。那么通常可以安全地假定 floatdouble大于long double。但如前所述,该标准并没有具体回答您的问题,因此它将是特定于实现的(尽管我知道没有一个违反您的陈述)
  • C 标准不要求“指针即指针即指针(任何给定实现只有一个大小)”是有原因的。原因是这对于几个(以前的)重要架构来说根本不正确。 c-faq.com/null/machexamp.html
  • "没有整数大于 sizeof(intmax_t)" - sizeof(intmax_t) 通常是 4 或 8。

标签: c sizeof


【解决方案1】:

现在有一个intptr_t 可以保证工作;然而,过去几年 intptr_t 需要大于 ptrdiff_t 的平台没有 intptr_t 因为它们被及时冻结,而目标平台的本机编译器只是没有它。如果你有一个像 OpenWatcom 这样针对旧架构的现代编译器,它会工作。

虽然他们确实为现代编译器对嵌入式 CPU 的交叉编译修复了这些问题,但您最终会遇到其他可能存在的异常,这些异常同样糟糕且同样难以测试。我不得不在嵌入式世界中处理的编译器有一些真正的麻烦。如果这些是典型的,那么尝试制作一个不假设扁平架构充满珍珠的平台中立库:

  • NULL 不是 0。这意味着 memset() 不会将结构中的指针初始化为 NULL,calloc() 也不会;除非显式初始化为 NULL,否则它们在声明为静态时也不为 NULL。
  • sizeof(char *) < sizeof(const char *)sizeof(void *) < sizeof(const void *);这个特定的编译器没有给出intptr_tptrdiff_t 不能包含在同一个字符数组中任意减去两个指针的结果(但可以通过使字符数组不大于 PTRDIFF_T_MAX 来避免)。
  • 编译器没有实现 C99 并且没有 intptr_t 并且 ptrdiff_t 太小而无法容纳指针。
  • free() 什么都没做
  • 编译器静态删除了空指针测试,它可以证明指针指向结构,但 NULL 是全局变量的可能地址。

我从未尝试过在嵌入式世界中创建一个重要的库,当然也从未尝试过像这样搞乱指针的库。

TL;DR 你所有的四个断言都应该是正确的,但是当你在重要的地方受到考验时,你最终会处理丑陋的事情。

如果您在指针和字符串之间进行转换,我会想到 sprintfsscanf 具有可以执行此操作的格式说明符。

【讨论】:

  • 第一句和最后一句都不对。
  • 其中 intptr_t 需要大于 ptrdiff_t 没有 intptr_t 我不明白为什么会这样,也不知道: 如果你不能安全地将指针投射到ptrdiff_tintmax_t 也根本不存在你能解释一下为什么会这样吗? AFAIK:对于某些 8051 编译器,此语句是错误的。
  • OpenWatcom for 8086 using the memory model LARGE 是一个编译器/库的例子,它使用 32 位的 intptr_t,但 ptrdiff_t 只是 16 位并且存在 intmax_t。是不是不符合规定? github.com/jmalak/open-watcom/blob/master/bld/hdr/watcom/…
  • @12431234123412341234123:大更新回答;我添加了很多来自嵌入式世界的东西。我很惊讶有人正在维护一个符合现代标准的 x86-16 编译器,但它就在那里,所以我将它包含在答案中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-08
  • 2012-03-15
  • 2017-10-20
  • 1970-01-01
  • 2011-04-28
  • 2020-09-08
  • 2023-04-02
相关资源
最近更新 更多