c++ - 在 extern "play"声明中使用参数常量对 "C"是否安全?

标签 c++ c language-lawyer cross-language extern-c

假设我正在使用一些具有函数的 C 库:

int foo(char* str);
我知道foo()不修改 str 指向的内存.只是写得不好,懒得声明str不变。
现在,在我的 C++ 代码中,我目前有:
extern "C" int foo(char* str);
我像这样使用它:
foo(const_cast<char*>("Hello world"));
我的问题:原则上,从语言律师的角度来看,在实践中,我这样写是否安全:
extern "C" int foo(const char* str);
并跳过 const_cast在吗?
如果不安全,请解释原因。
注意:我对 C++98 代码的情况特别感兴趣(是的,不幸的是我),所以如果你假设语言标准的更新版本,请这么说。

最佳答案

Is it safe for me to write: and skip the const_cast'ing?


不。

If it is not safe, please explain why.


——语言方面:
看完dcl.link我认为 C 和 C++ 之间的互操作性是如何工作的,并没有完全指定,有许多“不需要诊断”的情况。最重要的部分是:

Two declarations for a function with C language linkage with the same function name (ignoring the namespace names that qualify it) that appear in different namespace scopes refer to the same function.


因为它们指的是同一个函数,所以我相信一个合理的假设是,在 C++ 端声明具有 C 语言链接的标识符必须与在 C 端声明该符号兼容。在 C++ 中没有“兼容类型”的概念,在 C++ 中,两个声明必须是 相同 (转换后),使限制实际上更加严格。
从 C++ 方面,我们读到 c++draft basic#link-11 :

After all adjustments of types (during which typedefs are replaced by their definitions), the types specified by all declarations referring to a given variable or function shall be identical, [...]


因为声明int foo(const char *str) C++ 翻译单元中的 C 语言链接与声明不相同 int foo(char *str)在 C 翻译单元中声明(因此它具有 C 语言链接),行为未定义(著名的“无需诊断”)。
从 C 方面(我认为这甚至不需要 - C++ 方面足以使程序具有未定义的行为。无论如何),最重要的部分是 C99 6.7.5.3p15 :

For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types [...]


因为来自 C99 6.7.5.1p2 :

For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.


C99 6.7.3p9 :

For two qualified types to be compatible, both shall have the identically qualified version of a compatible type [...]


所以因为charconst 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));
}

关于c++ - 在 extern "play"声明中使用参数常量对 "C"是否安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64766291/

相关文章:

c++ - C(和 C++)中 char 的对齐是否保证为 1?

c++ - 如何使用 CMake 拥有多个二进制目录?

c - 我的程序在哪里犯了错误,我认为这是一个逻辑错误,但我找不到它

c++ - 我如何为 std::string 专门化我的模板

c - 摆脱||或者在 C 编程中

c - 传递给 C 中的方法时数组第一个元素的值更改错误

c - 有没有一种简单、可移植的方法来确定 C 中两个字符的顺序?

c++ - 允许转换为 void(不是指针),为什么?

c++ - Qsort比较函数

c++ - 在 C/C++ 中管理分层数据