我正在阅读John Regehr的博客,了解他如何给学生们一个关于饱和算术的任务.有趣的是,代码必须按原样编译,同时使用typedef指定不同的整数类型,请参阅以下完整标题的摘录:
typedef signed int mysint;
//typedef signed long int mysint;
mysint sat_signed_add (mysint, mysint);
mysint sat_signed_sub (mysint, mysint);
Run Code Online (Sandbox Code Playgroud)
相应的无符号版本很容易实现(虽然我实际上不确定填充位是否也不会产生问题),但我实际上看不出如何获得未知签名的最大值(或最小值)在C型,而无需使用宏MAX_UND MIN_或导致未定义的行为.
我在这里遗漏了什么,或者作业是否有缺陷(或者更可能是我错过了他给学生们的一些重要信息)?
我看不出有什么办法做到这一点不做假设或调用实现定义的(不一定是联合国定义的)行为.如果您认为有在表示没有填充比特mysint或者uintmax_t,然而,那么你就可以计算出这样的最大值:
mysint mysint_max = (mysint)
((~(uintmax_t)0) >> (1 + CHAR_BITS * (sizeof(uintmax_t) - sizeof(mysint))));
Run Code Online (Sandbox Code Playgroud)
那么最小值是-mysint_max(符号/幅度或1'补码)或-mysint_max - 1(2的补码),但确定哪个是有点棘手的.您不知道先验哪个位是符号位,并且可能存在不同表示形式的陷阱表示.您还必须小心评估表达式,因为"通常的算术转换"可能会将值转换为其表示具有与您尝试探测的属性不同的属性的类型.
尽管如此,可以通过计算的按位求反区分负值表示的类型mysint的表示-1.对于二进制补码,mysint结果的值是0,对于它的补码1,对于符号/幅度,它是mysint_max - 1.
如果添加所有带符号整数类型具有相同类型的负值表示的假设,则可以使用默认int文字上的普通表达式简单地执行此类测试.但是,您不需要做出这样的假设.相反,您可以通过以下方式直接对类型表示的位模式执行操作union:
union mysint_bits {
mysint i;
unsigned char bits[sizeof(mysint)];
} msib;
int counter = 0;
for (msib.i = -1; counter < sizeof(mysint); counter += 1) {
msib.bits[counter] = ~msib.bits[counter];
}
Run Code Online (Sandbox Code Playgroud)
只要初始假设成立(类型表示中没有填充位mysint),则msib.i必须是所需结果的有效表示.