【问题标题】:C/C++ linkage conventionC/C++ 链接约定
【发布时间】:2014-04-23 11:14:06
【问题描述】:

当调用像copy_if、transform等以一元或二元函数作为最后一个参数的C++算法时,我可以传递一个像atoi或tolower这样的C库函数吗?

例如下面的调用工作正常并给出正确的输出(在 ideone 中试过)

1) transform (foo, foo+5, bar, atoi);
2) transform (foo, foo+5, bar, ptr_fun(atoi));
3) transform(s.begin(),s.end(),s.begin(), static_cast<int (*)(int)>(tolower));

这种用法是否保证适用于所有 C++ 编译器?

《thinking in C++》一书提到“这适用于某些编译器,但不是必须的”。提到的原因是(据我了解)transform 是 C++ 函数,并期望其最后一个参数具有相同的调用约定。

该书还建议了解决此问题的方法,即在单独的 cpp 文件中创建这样的包装函数,并且不包含 iostreams 头文件。

// tolower_wrapper.cpp
string strTolower(string s) {
  transform(s.begin(), s.end(), s.begin(), tolower);
  return s;
} 

这很好用,但我不明白这如何解决调用约定问题? transform 仍然是一个 c++ 函数,而 tolower 在 strTolower 中仍然是一个 C 函数,那么这里如何处理不同的调用约定。

【问题讨论】:

  • 当由相同的编译器以相同的设置编译时,这些函数保证具有兼容的调用约定。
  • 调用约定不是“C 或 C++”,而是 cdecl、stdcall 之类的东西……我看不出它应该破坏这段代码的原因。
  • 这和链接有什么关系?
  • 这将永远有效.. 据我所知.. 我在 Linux Mint、MacOS Leopard 和 Windows 8.1 上进行了以下尝试:适用于 Clang++、G++、MSVC2010、MSVC2012、MSVC2013 , XCode(Obj-C++)..
  • @dyp 这就是我想了解的。在 cpp book 中的思想给出的确切解释是“原因,虽然晦涩难懂,是允许库实现提供“C 链接”(意味着函数名不包含普通 C++ 函数所做的所有辅助信息)到从 C 语言继承的函数。如果是这种情况,则转换失败,因为 transform 是 C++ 函数模板,并且期望它的第四个参数具有 C++ 链接——并且不允许强制转换来更改链接。这特别适用于例如3 以上。

标签: c++ c declspec


【解决方案1】:

首先要注意的是算法可以将函数指针或函数对象作为参数。

函数指针就是这样 - 一个指向函数的指针,该函数期望接受一组特定的参数并返回特定的类型。

一个函数对象是一个类的实例,它被重写了 operator()。

在扩展算法模板时,编译器将能够看到两种情况中的哪一种适用,并生成适当的调用代码。

如果 C 函数在算法中用作二进制函数,则它是您提供的函数指针。您可以从 C++ 中调用 C 函数,只要它声明为 extern C { ... }

许多编译器都带有 C 库函数的头文件,其中包括如下内容:

#ifdef  __cplusplus
extern "C" {
#endif

/* function declarations here */

#ifdef  __cplusplus
}
#endif

因此,如果您包含来自 C++ 程序的 C 库头文件,则包含的所有函数都将神奇地可供您使用。但是,该部分不受标准的保证,这就是为什么您的书指出它可能不适用于所有编译器。

另一个问题是,您不允许将函数指针转换为具有不同语言链接的类型,至少在您正在执行的某些示例中,尽管有些编译器似乎确实允许这样做 - 例如看这个GCC Bug.

另一个特别适用于tolower 的问题是,C 库函数的某些名称也是 C++ 标准库中的函数或模板的名称。例如,名称 tolower 也在&lt;locale&gt; 中定义。这个具体案例在GCC bug report 中讨论。使用在不包含冲突声明的单独编译单元中编译的包装器可以解决此问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-02
    • 2014-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多