下面是一个读取行的函数的简短片段。它怎么可能将bufsize
与((size_t)-1)/2
进行比较?
我想象着将一个变量与例如int
进行比较——这是不可能的;相反,我认为INT_MAX是正确的。那么,这些代码如何才能真正工作并且不出错呢?
int c;
size_t bufsize = 0;
size_t size = 0;
while((c=fgetc(infile)) != EOF) {
if (size >= bufsize) {
if (bufsize == 0)
bufsize = 2;
else if (bufsize <= ((size_t)-1)/2)
bufsize = 2*size;
else {
free(line);
exit(3);
}
newbuf = realloc(line,bufsize);
if (!newbuf) {
free(line);
abort();
}
line = newbuf;
}
/* some other operations */
}
(size_t)-1
这是将值-1
强制转换为size_t
。(type)value
是C
由于size_t
是一个无符号类型,这实际上是size_t
可以保持的最大值,因此它用于确保缓冲区大小实际上可以安全地加倍(因此随后可以除以2)。
该代码依赖于一些关于比特的假设,然后进行众所周知的破解来找到最大size_t值(前提是size_t不能容纳比寄存器更多的比特,这在许多机器上是安全的)。
首先,它用1
位填充寄存器,然后将其强制转换为size_t
数据类型,这样比较就可以工作了。只要该寄存器的位数大于size_t
数据类型,则未使用的1
位(如果有)将被截断,您将获得可容纳size_t
位的最大无符号数。
之后,它除以2得到该数字的一半,并进行比较,看看在不超过"最大"size_t
的情况下增加大小是否安全。但到那时,它将划分一个size_t
数据类型,并比较两个size_t
数据类型(类型安全操作)。
如果你真的想去掉这个小魔法(好吧,这不是我见过的最糟糕的小魔法例子)。考虑以下片段
else if (bufsize <= ((size_t)-1)/2)
bufsize = 2*size;
可以用代替
else if (bufsize <= (MAX_SIZE/2)
bufsize = 2*size;
并且是类型安全的而不进行强制转换并且更可读。
(size_t)-1
将-1
强制转换为类型size_t
,从而产生SIZE_MAX
(在stdint.h中定义的宏),这是size_t
类型可以容纳的最大值。
因此,比较是检查bufsize
是否小于或等于size_t
中可包含的最大值的一半
size_t没有被解释为一个值,它被用来将负1的值强制转换为size_t类型。
((size_t)-1)/2
是将-1强制转换为size_t,然后除以2。
((size_t)-1)/2)
中的size_t
只是用作强制转换:将-1
强制转换为size_t
。
这里的技巧是size_t
是无符号的,因此转换后的(size_t) -1
将转换为size_t
或SIZE_MAX
的最大值。这在循环的上下文中很有用。然而,我更希望看到SIZE_MAX
直接使用,而不是这个技巧。