为什么有些库使用非常量char*作为函数参数?
有时在我的 C++ 项目中使用纯 C 库,我会看到奇怪的(在我看来)函数声明。
例如:libldap 的ldap_search_ext():https ://linux.die.net/man/3/ldap_search_ext_s
int ldap_search_ext(
LDAP *ld,
char *base,
int scope,
char *filter,
char *attrs[], // this one!
int attrsonly,
LDAPControl **serverctrls,
LDAPControl **clientctrls,
struct timeval *timeout,
int sizelimit,
int *msgidp );
为什么 attrs[] 不能是 a const char *?
像这样的声明不想改变指针的内容并产生很多问题:
// pure C
void func(char * data[])
{
...
}
func({"blabla"}); // won't work (corrected: yes, this is wrong syntax, but it's true for structs of pointers)
const char *d[] = {"blabla", "blablu"};
func(d); // won't work
// C++
const std::string str("blabla");
char * data[] = { str.data() }; // even non-const won't work (because data() returns const*)
/// etc...
是否有任何理由不将此类参数声明为 const?
回答
这主要是(由于)C 标准中从未修复的历史问题。
当const被添加到 C 时,添加了隐式(和安全)转换简单指针的能力——你可以隐式地将 a 转换T *为 aconst T *就好了。然而,更复杂的指针类型的(安全)转换被遗漏了——你不能将 a 转换T * const *为 a const T * const *。结果,当一个库采用这样的双指针时,const如果它是只读的,它就没有任何“好”的方法来制作它。使其成为 aconst char **或 aconst char * const *会破坏某些用途(需要凌乱的显式强制转换)。
请注意,允许T **to 的隐式转换const T **是不安全的——这样的指针可用于修改 aT *指向 aconst T *而不进行强制转换。
回答
一个可能的原因是 C 中的字符串常量(与 C++ 不同)不是const.
因此,许多本应存在的库在历史上缺乏常量正确性。如果字符串常量是const,程序员将不得不考虑它。
在处理诸如此类的库时,您知道不会修改参数,您必须应用 aconst_cast使其适合。
char *d[] = {const_cast<char *>("blabla"), const_cast<char *>("blablu")};
func(d);
const std::string str("blabla");
char * data[] = { const_cast<char *>(str.data()) };
func(data);