现代编译器可以在看到const
时优化代码。 但是,我从未见过C标准库使用const
作为非指针参数。例如memcmp()
就是一个例子。它有2个const void *
个参数,但它的第三个参数是size_t
。
为什么标准库(和其他库)以这种方式设计?为什么我在现代代码中看不到const size_t
或const int
?
答案 0 :(得分:6)
C使用call-by-value。它没有帮助编译器将函数参数标记为const
(注意memcmp()
的任何参数都不是const
。指针参数也可以声明为{{1}你可以建议它们应该是:const
。但它们不是。)
它无法帮助编译器标记函数参数int memcmp(const void * const s1, const void * const s2, size_t const n);
的原因是,从函数的角度来看,函数参数只是一个局部变量。只要该函数不采用其地址,编译器就很容易看到该变量永远不会被修改。
相比之下,属于const
原型的const
修饰符(memcmp()
)
它是合同的一部分:它们表示该函数不会修改指向的数据。 const void *s1
修饰符从不以这种方式用于参数本身,因为调用者不关心函数是否修改其参数:它们只是副本(因为C使用call-by-value)。
答案 1 :(得分:4)
那些const
意味着不同的东西。在
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
const void * ptr1
表示memcmp
会将ptr1
视为指向常量数据并且不会对其进行修改;同样适用于const void * ptr2
。因此,呼叫者知道存储的值将不会改变并且可以相应地进行优化。在像
int result = memcmp(ptr1, ptr2, num);
将变量ptr1
,ptr2
和num
复制到函数中。 memcmp
不承诺不调整它们;它只承诺不调整指针指向的内容。实际上,它可以递增/递减任何复制的变量,以便在证明有效的情况下逐步执行数组。如果它想要保证不改变它们中的任何一个,声明将是:
int memcmp ( const void *const ptr1, const void *const ptr2, const size_t num );
对于简单数据类型(如指针和整数),可以通过这种方式获得很少(如果有)优化,并且此函数(和其他)的原始说明符显然没有理由阻止实现修改变量偶然的情况。
答案 2 :(得分:0)
这是图书馆一致性的主要原因。将size_t
参数更改为const size_t
将需要修改大小的库被重写。并非所有库的实现都需要使用相同的算法。这是现有库函数未被调整的主要原因。
通常使用非const
参数有目的地创建新的库函数,以便某些依赖于机器的实现可以使用可修改的参数。
例如,英特尔C ++编译器版本memcmp
实际上在执行期间倒计时length
参数。其他一些实现可能不会这样做。