【问题标题】:How to portably check extremal values for SuSv3 data types?如何可移植地检查 SuSv3 数据类型的极值?
【发布时间】:2014-01-22 10:45:54
【问题描述】:

SuSv3 要求ssize_t 是有符号整数类型。如果我想检查我计算的值是否大于此类数据类型允许的最大值,我可以将其与INT_MAX 进行比较,这不太好。

有没有一种更便携的方式可以完成这种比较 - 一个宏/函数f,就像在

中一样工作
 f(<typedef'ed datatype>) = {maximum value allowed for <TDDT> on this system)?

,还是短序列的这样的操作相同的排序?

系统:
Ubuntu 12.04.
glibc 2.15
内核 3.2.0

P.S.:在谷歌上搜索时,我首先认为 gcc 扩展“typeof”听起来很有希望;但它似乎在这里没有帮助(或者是吗?)。这就是说我可以接受任何可能是 gcc 扩展/属性/等的东西。

【问题讨论】:

  • "我可以将它与 INT_MAX 进行比较,这不太好。" 为什么?还是您指的是与INT_MAX 进行比较以测试该值是否适合ssize_t?这确实不太好,因为应该使用-((SIZE_MAX+1)/2-1)
  • @alk:也许我的想法有缺陷,但我的意思是保持与 SuS 标准(或其继任者)可能需要的 ssize_t 的任何未来变化(这显然只是一个示例数据类型) .似乎不太可能发生变化,但是如果在未来的修订版中 typdef int ssize_t (同样,显然只是一个例子)怎么办?我正在通过 Kerrisk 以我的方式工作,这个问题浮现在我的脑海中。或者,在这种情况下,标准 API 编码会使用 INT_MAX 吗?
  • ...我的意思是输入 typedef unsigned int ssize_t...
  • 如果您需要特定的位宽,请坚持使用u/intXY_t 整数类型,因为它们的宽度是明显且恒定的,因此您不需要使用 MIN/MAX 宏。对于像s/size_tu/intprt_tptrdiff_t 这样的其他人来说,位宽并不重要,因为它们被明确引入以解决位宽问题。所以请原谅,但我真的不明白你的问题的重点。

标签: c++ c typedef type-conversion sus


【解决方案1】:

对于无符号算术类型,(type)-1 是最大值。由于您不知道类型的相对大小是多少,因此转换为uintmax_t

#define UNSIGNED_TYPE_MAX(t) ((uintmax_t)(t)-1)
if ((uintmax_t)x > UNSIGNED_TYPE_MAX(size_t)) puts("too large");

签名类型没有这样的快捷方式。事实上,我认为在严格可移植的 C89 或 C99 中没有任何方法可以确定带符号类型的最大值,而不使用相应的常量,例如 SSIZE_MAX for ssize_t。对于 ISO C 中定义的类型,C99 为 stdint.h 中定义的每种算术类型指定常量。对于 POSIX 中定义但标准 C 中未定义的类型,limits.h 中有许多值;请注意,它们是类型预期的有效值的限制,而不是可以适合类型的限制。例如,如果 size_t 是 32 位类型,则 SIZE_MAX 保证为 232-1,而 SSIZE_MAX 可能小于 231-1 如果实现不支持任何大于此的字节数。

假设整数以二进制表示并且没有填充位,如果您将自己限制为 POSIX(其中CHAR_BITalways 8),这是安全的,您可以通过计算推导出最大值类型的大小:有符号类型中只有一个符号位,其他都是值位。

#define SIGNED_TYPE_MAX(t) (((uintmax_t)1 << (sizeof(t) * CHAR_BIT - 1)) - 1)

请注意,诸如“加倍直到停止增长”或“推入位模式 0111…111”之类的内容是不可靠的。 C 标准说有符号类型的行为是未定义的,GCC 利用这一点对有符号类型的操作执行优化,如果发生溢出,可能会导致错误值。例如,它可能会在更大的寄存器中执行计算,这样就不会发生溢出。

【讨论】:

  • Tyvm!这很聪明,但请允许我提出一些后续问题(如前所述,我对此很陌生):(i)uintmax_t 到底是什么(这个名字很清楚,但这是我第一次看到数据类型),(ii)我什至不知道常量 SSIZE_MAX 存在(但现在在 posix1_lim.h 中找到了它(谢谢!) - 但是,说 SIZE_MAX 不存在,对吗? POSIX typdefs 这样的常量存在吗?(iii)CHAR_BIT 到底是什么(我理解你上次#define 的逻辑;但也不知道这个)。
  • 如果您认为这值得提出一个单独的问题,以免过度搭便车,我可以投票赞成,我很乐意提出另一个问题。 --add--再看一遍,我注意到 SSIZE_MAX 实际上是 LONG_MAX,所以我最初使用 INT_MAX 的建议是双重可疑的。
  • @gnometorule:搜索标准 C 标头 &lt;limits.h&gt;&lt;stdint.h&gt;&lt;inttypes.h&gt;
  • @gnometorule 我已经为适当的标头添加了指向 Single Unix 规范的链接。使用标准标头名称,posix1_lim.h 是一个内部的、不可移植的标头名称。 SIZE_MAX 确实存在。 CHAR_BIT 是每个字节的位数。并非所有 POSIX 类型都有定义的限制,只有用于计算的限制,并非所有用于系统句柄的限制,例如 uid_t
  • 这太棒了,非常感谢。按照@mafso 的建议,我已经在 stdint.h 中找到了 uintmax_t,现在将检查其余部分。
猜你喜欢
  • 2016-06-10
  • 2019-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-17
  • 2010-10-01
  • 1970-01-01
  • 2014-01-24
相关资源
最近更新 更多