为什么bsearch返回一个void*?
如果我传入了一个为什么bsearch返回一个void*?,c,pointers,constants,void,bsearch,C,Pointers,Constants,Void,Bsearch,如果我传入了一个const void*base,那么b搜索不应该也返回一个const void*结果吗?当你搜索某个东西时,它是一个有效的请求,你可以在找到它后修改它。如果搜索功能不允许你这样做,那就太严格了。当然,这样的修改可能会破坏后续的搜索,但那是另一回事 参数是常量,这是合理的,因为bsearch本身不会修改它们。向指向类型添加限定符是一种隐式转换,而删除限定符需要显式转换 bsearch()的原型的编写方式允许以下两种用法,而无需显式转换: void * bsearch ( const
const void*base
,那么b搜索
不应该也返回一个const void*
结果吗?当你搜索某个东西时,它是一个有效的请求,你可以在找到它后修改它。如果搜索功能不允许你这样做,那就太严格了。当然,这样的修改可能会破坏后续的搜索,但那是另一回事
参数是常量,这是合理的,因为bsearch本身不会修改它们。向指向类型添加限定符是一种隐式转换,而删除限定符需要显式转换
bsearch()
的原型的编写方式允许以下两种用法,而无需显式转换:
void * bsearch ( const void * key,
const void * base,
size_t num,
size_t size,
int ( * comparator ) ( const void *, const void * ) );
然而,这意味着可以使用bsearch()
——以及许多其他libc函数——在没有警告的情况下删除const限定,例如如果我们编写了
int needle = 0xdeadbeef;
int foo[42] = { ... };
int *p = bsearch(&needle, foo, 42, sizeof *foo, cmpi);
const int bar[42] = { ... };
const int *q = bsearch(&needle, bar, 42, sizeof *bar, cmpi);
这是完全合法的:未定义的行为只有在我们实际使用q
修改bar
时才会发生
您还应该记住,常量限定指针参数只会影响哪些参数在没有强制转换的情况下被接受,但不能保证函数不会修改指向的对象。这仅仅是一个几乎所有现有代码都遵循的约定,但语言语义并不强制执行
特别是,编译器不能在调用代码中使用此信息进行优化-编译器需要查看函数体,因为如果对象本身未声明为const
,则从指针中删除const限定并修改指向的对象是合法的
在过去,我假设额外限制限定指针参数将强制执行不变性,但仔细重读第6.7.3.1节,我认为情况并非如此:限制限定指针指向的对象上的约束仅在指针实际用于访问对象时生效,但是调用代码不能仅仅从原型中做出这样的假设…我认为这是C的类型系统中最大、最恼人的缺陷。另一个例子是
strchr
,这是一个具有完全相同问题的函数:它返回指向用户传入的资源的指针。此函数需要对常量和非常量输入参数都有用。你看到的是一种妥协
我发现这样的访问者最讨厌:
int *q = bsearch(&needle, bar, 42, sizeof *bar, cmpi);
对于内部使用,宏是一个很好的“多态”实现
const struct list *list_next(const struct list *x) { return x->next; }
但是对于外部使用,您必须使用
b搜索
折衷或两个单独的函数list\u next
和list\u next\u const
如果某个东西作为const void*
提供给您怎么办?你已承诺不修改它。您不应该请求修改的能力。但是,由于C不能重载函数,我猜这是你必须忍受的妥协。@ r.MARTIHHOFNANDENES,即使在C++中,也不能简单地通过返回类型来加载。@ XANATOS,但是您也会超载于参数!code>const-void*b搜索(const-void*key,…)和void*b搜索(void*key,…)
。考虑到void*
需要被转换成任何有用的东西,我认为它不是一个很强的参数:-),但通过将它与strstr进行比较(这与bsearch类似),我们可以看到这一论点的“智慧”(他们想要统一)@R.MartinhoFernandes对base
;)的常量进行重载更有意义。如果const
不限制对对象的修改,也不帮助编译器优化,那么const
的意义是什么?@Andrey:const
会限制对对象的修改,但const*
不;在某种程度上,标记指针参数const
只是一种语法考虑:它允许在不使用强制转换的情况下传入const限定对象的地址,但没有真正的语义差异;然而,const*restrict
参数在语义上是不同的,但restrict
只影响被调用对象,而不影响被调用对象调用codeArestrict
指针只要求所有指向对象的访问都直接或间接使用此指针的值。这与常量有任何关系吗?@Andrey:这是一种简化;更正式地说:如果对象是(1)通过基于限制限定指针的表达式访问,并且(2)修改了对象,则(a)指针不能是常量限定的,并且(b)所有访问(包括修改)必须基于该指针;特别是,由限制限定指针指向常量的对象根本不能修改(在该指针的生命周期内),但仅当该指针用于访问该对象时,即只要该指针从未被使用,则修改是合法的(!);(更多…(…)(a)是必需的,因为如果它不存在,您可以将限制限定指针移到const,将const
抛出,并合法地使用该表达式修改指向的对象;这意味着const*restrict
比const*
和*restrict
语义的组合具有更强的约束
#define LIST_NEXT(x) ((x)->next)