我这样写安全吗:跳过 const_cast'ing?
不。
如果不安全,请说明原因。
-- 从语言方面:
在阅读了dcl.link之后,我认为 C 和 C++ 之间的互操作性究竟是如何工作的并没有完全指定,有许多“不需要诊断”的情况。最重要的部分是:
出现在不同名称空间范围内的具有相同函数名称(忽略限定它的名称空间名称)的具有 C 语言链接的函数的两个声明指的是同一个函数。
因为它们引用相同的函数,所以我相信一个合理的假设是,在 C++ 端声明具有 C 语言链接的标识符必须与在 C 端声明该符号兼容。在 C++ 中没有“兼容类型”的概念,在 C++ 中,两个声明必须相同(在转换之后),这使得限制实际上更加严格。
从 C++ 方面,我们阅读c++draft basic#link-11:
在所有类型调整之后(在此期间 typedef 被其定义替换),引用给定变量或函数的所有声明指定的类型应相同,[...]
因为int foo(const char *str)
在 C++ 翻译单元中具有 C 语言链接的声明与在 C 翻译单元中声明的声明不同int foo(char *str)
(因此它具有 C 语言链接),所以行为是未定义的(著名的“无需诊断”)。
从 C 方面(我认为这甚至不需要 - C++ 方面足以使程序具有未定义的行为。无论如何),最重要的部分是C99 6.7.5.3p15:
对于要兼容的两种函数类型,两者都应指定兼容的返回类型。此外,参数类型列表(如果两者都存在)应在参数数量和省略号终止符的使用方面达成一致;相应的参数应具有兼容的类型 [...]
因为从C99 6.7.5.1p2 开始:
对于要兼容的两种指针类型,两者都应具有相同的限定,并且都应是指向兼容类型的指针。
和C99 6.7.3p9:
对于要兼容的两种合格类型,两者都应具有兼容类型的相同合格版本 [...]
所以因为char
不兼容const char
,所以const char *
不兼容char *
,所以int foo(const char *)
不兼容int foo(char*)
。调用这样的函数(C99 6.5.2.2p9)将是未定义的行为(您可能还会看到C99 J.2)
——从实际方面:
我不相信能够找到一个编译器+架构组合,其中一个翻译单元看到int foo(const char *)
而另一个翻译单元定义了一个函数int foo(char *) { /* some stuff */ }
并且它“不起作用”。
从理论上讲,一个疯狂的实现可能使用不同的寄存器来传递const char*
参数和不同的寄存器来传递char*
参数,我希望在那个疯狂的架构 ABI 和编译器中能很好地记录这一点。如果是这样,错误的寄存器将用于参数,它将“不起作用”。
尽管如此,使用简单的包装器仍然没有任何成本:
static inline int foo2(const char *var) {
return foo(static_cast<char*>(var));
}