我一直在尝试处理我正在编写的简单c库中的错误。检查参数错误(或拼写错误)的最佳做法是什么?假设我有这样的函数:
int foo (size_t maxSize); // (the int returned is an error type)
然后让我们说foo
继续创建一个maxSize
元素数组。我的问题是这样的:如果有人使用带有负数的foo
,则此数字会被解释为size_t
,并且可能会在没有警告的情况下变得非常大:
printf ("zu", -10); // 4294967286 on my machine
程序编译时没有错误或警告,foo
尝试创建一个巨大的数组,程序在运行时停止,并且没有直接的方法来找到foo
是原因(我的灵魂)
如何妥善处理?在foo
检查到它是肯定的后,long
应该将size_t
作为foo
投射吗? (然后返回相应的错误?)。或size_t
foo
是否应保留int foo (size_t maxSize)
而不打扰不关注size_t
签名的用户?
编辑答案:
一致保留真实签名MaintenanceOrders
,否则会产生误导(因为MaintenanceOrders
的最大值是有效参数)。让用户处理它,也许可以帮助他完成文档。
答案 0 :(得分:3)
您的库的问题是foo
应创建的最大尺寸数组是什么?传递size_t
的最大大小是错误吗?如果没有,那么你的图书馆无法判断错误的通话和想要创建一个非常大的数组的合法通话。如果您无法判断输入是否无效,那么您应将其视为有效。您图书馆的用户有责任发现这些错误。
答案 1 :(得分:1)
检查高位设置的参数的额外代码似乎过多。用防御性编码过度使用它并不是很好;它膨胀了源代码并使二进制文件更慢。
使用你的图书馆的人有责任不传递虚假的args,比如负值作为一个大小。
确保您的代码在分配失败时不会崩溃或泄漏内存,并且在这种情况下返回错误代码。我认为这是最好的方法。如果有人以负面大小调用您的函数,这是一个主要错误,并且干净地返回错误似乎是让它们易于调试的最佳方式。
答案 2 :(得分:1)
或者应
foo
保持size_t
而不打扰那些不遵循foo签名的用户?
是。
如果输入参数未出现负值(未定义),请不要对其进行签名。
如果您很高兴,请添加到您的文档中,以便以最高警告级别编译潜在的生产代码。
答案 3 :(得分:-2)
无符号整数(如size_t
)的下溢是例如:UINT_MAX
unsigned int
。它们环绕,所以说,行为在标准中定义:
否则,如果新类型是无符号的,则通过重复添加o比新的typ中可以表示的最大值减去一个来转换该值,直到该值在新类型的范围内.60)< / p>
ISO 1999:2011 sec.6.3.1.3
size_t
的最小尺寸(在ISO 1999:2011 7.19,stddef.h
附件B.18中描述)为SIZE_MAX
(在ISO 1999:2011 7.20.3中描述,设定在stdint.h
附件B.19)
其实现定义值的大小应等于或大于等于 (绝对值)比下面给出的相应值,具有相同的符号。
ISO 1999:2011 7.20.3
但是,从报价中可以看出,只有最小值。你可以做的是通过例如隐含地触发转换:
size_t size_t_max = (size_t) -1;
并检查maxSize
的输入foo
是否大小。
<强>被修改强>
我不知道这是我的英语不好还是对一个委员会的行业标准建设的基本误解,该委员会的成员来自不同公司,他们都试图将他们的特殊兴趣纳入标准。这就是“这个和那个被定义为具有这些值,但......”形式的许多妥协的原因,其后是一堆例外,或者在编程语言的标准可以非常接近的情况下使用像C这样的硬件,定义了最小值,其余的给出了“单独实现”。
没有多少人有这个问题(除了那些必须为该语言构建编译器的穷人;-)),这是你从委员会得到的,这是预期的结果:只有最低的共同点得到了结论,其余的是“实施定义”。面对重复自我的危险面貌:这没有问题。
这导致了很多变通办法和其他怪癖,就像这里的问题一样。
size_t
的数据类型必须是无符号的,并且能够保存至少2 ^ 16的数字(为简单起见称为“大小”)。就这些。如果需要,用于size_t
的数据类型可能会保留更多,甚至超过SIZE_MAX
。
C标准不是仅针对x86er CPU编写的,而是针对更多内容,尤其是现在可以购买的数百种小型嵌入式处理器。它们中的许多具有不同于32或64的整数位长度。例如,一些具有24位大整数。利用如此大量的不同大小的整数,LibC对它的写入可以非常自由地选择他们想要的东西,例如:一个size_t
。他们还可以选择您想要的值SIZE_MAX
,例如:您可以为该处理器提供的最小内存量。
这意味着您可以假设关于size_t
和SIZE_MAX
的连接的唯一事情是,size_t
使用的整数类型的大小必须能够保持至少{{ 1}}。这导致得出的结论是,在运行时知道SIZE_MAX
的参数bar
是否为负的唯一符合C标准的方法是获得用于foo(size_t bar)
的整数类型的最大大小通过size_t
有意识地导致下溢(或如果你想要的环绕),这是一个明确定义的行为。
仅仅测试size_t size_t_size = (size_t) -1;
是不够的,因为> SIZE_MAX
可能大于bar
,但仍然不是负数。
仍然存在的问题是,如果通过将带有负值的有符号整数作为定义为无符号的参数传递,可以预期定义良好的行为。我想说:是的,因为从有符号到无符号的转换是明确定义的(在6.3.1.8和6.3.1.3中的实际转换)。