【发布时间】:2016-05-25 02:44:18
【问题描述】:
在某些 C99 代码中,我需要检查变量 i 是否在区间 [0, max] 中,其中已知 max 为正数。问题是变量的类型允许有符号和无符号(通过更改typedef)。如何最好地检查变量是否在区间内?
直接的方法是:
bool is_in_interval(my_type i, my_type max) {
assert(max > 0);
return (i >= 0 && i <= max);
}
当我们有typedef int my_type; 时,这将正常工作。但是当my_type 是无符号的(即typedef unsigned int my_type;)时,i >= 0 总是正确的,编译器会(正确地)警告它,我想避免这种情况。 (我不想关闭该警告,因为当这种比较实际上是无意的时它很有用,并且忽略编译器警告不是一个好主意。)
我目前的想法是将i 转换为无符号类型,然后只检查上限:
bool is_in_interval(my_type i, my_type max) {
assert(max > 0);
return ((size_t) i <= (size_t) max);
}
如果有符号类型具有二进制补码表示,则任何负值都应该大于max,一旦转换为无符号版本,对吗?如果是这样,这应该工作。但是,我不确定这是否是一种可取的方法。例如,假设签名类型在所有平台上都使用二进制补码是否安全?有没有更好的方法来做到这一点?
【问题讨论】:
-
当您的签名测试值(解释为
unsigned)可能大于(无符号)MAX/2时,这将不起作用。可以这样吗? (嗯。也许我的意思是小于。) -
我很确定可以保证转换为兼容的无符号类型的负值将大于原始类型的任何正值。然而,如果你这样做,你会让人们抱怨“奇怪的代码”。
-
@Jongware 对不起,我不太明白你的意思。
MAX不是类型的限制(例如,INT_MAX或UINT_MAX)。使用大写字母具有误导性(现在已更改)。 -
@JohnColeman 我对忽略编译器警告没有任何宗教厌恶。但是,我认为应该没有是一个很好的经验法则。否则,必须跟踪警告正常和不正常的文件和行号。在这种情况下,错过真正问题的风险似乎很高。
-
A C 实现可以具有比
size_t'更宽'(非正式地,更大)的整数类型,如果是这样,则强制转换可能会更改值并给您错误的结果。来自<stdint.h>的uintmax_t可移植地避免这种情况(在C99 及更高版本中,但您说的是C99)。 OTOH 2sC 不是问题;在 C 中将有符号整数转换为无符号定义即使在(非常非常罕见的)1sC 或 S&M 机器上也可以有效地将 w 加或减 2。
标签: c