我正在阅读一本教科书,其中一个例子就是这样做的。下面,我以缩写形式复制了这个例子:
#include <stdio.h>
#define SIZE 100
size_t linearSearch(const int array[], int searchVal, size_t size);
int main(void)
{
int myArray[SIZE];
int mySearchVal;
size_t returnValue;
// populate array with data & prompt user for the search value
// call linear search function
returnValue = linearSearch(myArray, mySearchVal, SIZE);
if (returnValue != -1)
puts("Value Found");
else
puts("Value Not Found");
}
size_t linearSearch(const int array[], int key, size_t size)
{
for (size_t i = 0; i < size; i++) {
if (key == array[i])
return i;
}
return -1;
}
这有什么潜在的问题吗?我知道size_t被定义为无符号整数类型,所以如果我将-1作为size_t返回值返回-1,似乎这可能会在某些时候遇到麻烦。
答案 0 :(得分:2)
有一些API可以使用最大有符号或无符号整数值作为标记值。例如,如果在字符串中找不到std::string::npos
的值,并且find()
等于std::string::npos
,则C ++的std::string::find()
方法会返回(std::string::size_type)-1
。< / p>
同样,在iOS和OS X上,当在数组中找不到对象时,NSArray
的{{3}}方法返回NSNotFound
。令人惊讶的是,NSNotFound
实际上定义为NSIntegerMax
,对于32位平台,INT_MAX
或64位平台为LONG_MAX
,即使NSArray
索引通常为NSUInteger
(对于32位平台,unsigned int
或64位平台为unsigned long
。
这确实意味着“未找到”和“元素编号18,446,744,073,709,551,615”(对于64位系统)之间没有区别,但这是否是可接受的权衡取决于您。
另一种方法是让函数通过指针参数返回索引,并使函数的返回值表示成功或失败,例如
#include <stdbool.h>
bool linearSearch(const int array[], int val, size_t size, size_t *index)
{
// find value and then
if (found)
{
*index = indexOfFoundItem;
return true;
}
else
{
*index = 0; // optional, in some cases, better to leave *index untouched
return false;
}
}
答案 1 :(得分:1)
你的编译器可能会决定抱怨比较签名与未签名 - GCC或Clang将被激活 * - 但否则“它工作”。在二进制补码机器上(这些天大多数机器),(size_t)-1
与SIZE_MAX
相同 - 实际上,正如评论中的扩展中所讨论的那样,对于一些补码或符号幅度的机器来说它是相同的因为C99和C11标准的第6.3.1.3节中的措辞。
使用(size_t)-1
表示“未找到”意味着您无法区分最大可能数组中的最后一个条目和“未找到”,但这很少是实际问题。
那么,这只是我可能最终遇到问题的一个边缘情况?
数组必须是char
的数组,但要大到足以引起麻烦 - 虽然你可以使用32位机器拥有4 GiB内存,但拥有所有这些内容却相当不可思议内存提交给一个字符数组(并且它不太可能成为64位机器的问题;大多数不会运行到16个exbibytes内存)。所以这不是一个实际的边缘案例。
在POSIX中,有一个ssize_t
类型,即size_t
大小相同的签名类型。您可以考虑使用它而不是size_t
。然而,根据我的经验,它引起(size_t)-1
导致的同样焦虑。另外,在32位计算机上,你可以将3 GiB内存块视为char
数组,但如果使用ssize_t
作为返回类型,则无法使用超过2 GiB - 或者您需要使用SSIZE_MIN
(如果它存在;我不确定),而不是-1
作为信号值。
*
GCC或Clang必须相当努力。仅使用-Wall
是不够的;需要-Wextra
(或特定的-Wsign-compare
选项)才能触发警告。由于我经常用-Wextra
编译,我知道这个问题;不是每个人都保持警惕。
比较有符号和无符号的数量是由标准完全定义的,但可能导致反直觉的结果(因为当转换为无符号值时,小的负数看起来非常大),这就是编译器在请求的情况下抱怨的原因。
答案 2 :(得分:0)
通常,如果您想要返回负值并且仍然有一些大小类型的概念,则使用ssize_t
。 gcc和clang都抱怨,但以下编译。注意,以下一些是未定义的行为......
#include <stdio.h>
#include <stdint.h>
size_t foo() {
return -1;
}
void print_bin(uint64_t num, size_t bytes);
void print_bin(uint64_t num, size_t bytes) {
int i = 0;
for(i = bytes * 8; i > 0; i--) {
(i % 8 == 0) ? printf("|") : 1;
(num & 1) ? printf("1") : printf("0");
num >>= 1;
}
printf("\n");
}
int main(void){
long int x = 0;
printf("%zu\n", foo());
printf("%ld\n", foo());
printf("%zu\n", ~(x & 0));
printf("%ld\n", ~(x & 0));
print_bin((~(x & 0)), 8);
}
输出
18446744073709551615
-1
18446744073709551615
-1
|11111111|11111111|11111111|11111111|11111111|11111111|11111111|11111111
我在64位机器上。二进制文件中的以下内容
|11111111|11111111|11111111|11111111|11111111|11111111|11111111|11111111
可以表示-1
或18446744073709551615
,它取决于上下文,即以何种方式使用具有该二进制表示的类型。