名称或类型具有某种语言链接意味着什么?

2024-02-10

根据 (c) ANSI ISO/IEC 14882:2003,第 127 页:

联动规格嵌套。当链接规范嵌套时,最里面的规范决定语言。链接规范不建立范围。链接规范仅应出现在名称空间范围内 (3.3)。在链接规范中,指定的语言链接适用于声明引入的所有函数声明符、函数名称和变量名称的函数类型。

extern "C" void f1(void(*pf)(int));
// the name f1 and its function type have C language
// linkage; pf is a pointer to a C function

extern "C" typedef void FUNC();
FUNC f2;
// the name f2 has C++ language linkage and the
// function's type has C language linkage

extern "C" FUNC f3;
// the name of function f3 and the function's type
// have C language linkage

void (*pf2)(FUNC*);
// the name of the variable pf2 has C++ linkage and
// the type of pf2 is pointer to C++ function that
// takes one parameter of type pointer to C function

这是什么意思呢?例如,什么联系f2()函数有,C或C++语言联动吗?

正如@Johannes Schaub 所指出的,标准中没有真正解释这意味着什么,因此在不同的编译器中可以有不同的解释。

请解释一下目标文件中的差异:

  • 具有 C 语言链接和 C++ 语言链接的函数名称。
  • 具有 C 语言链接和 C++ 语言链接的函数类型。

语言链接是用于表示之间链接的术语C++ and non-C++代码片段。通常,在 C++ 程序中,所有函数名称、函数类型甚至变量名称都具有默认的 C++ 语言链接。

C++ 目标代码可以链接到使用其他源语言(例如C) 使用预定义的链接说明符。

正如您必须意识到的概念name mangling,它对函数名称、函数类型和变量名称进行编码,以便为它们生成唯一的名称。这允许链接器区分通用名称(如函数重载的情况)。将 C 模块与使用 C++ 编译器编译的库或目标文件链接时,名称重整是不可取的。为了防止这种情况下的名称修改,使用了链接说明符。在这种情况下,extern "C"是链接说明符。我们举个例子(提到的c++代码here http://developers.sun.com/solaris/articles/mixing.html):

typedef int (*pfun)(int);  // line 1
extern "C" void foo(pfun); // line 2
extern "C" int g(int)      // line 3
...
foo( g ); // Error!        // line 5

第 1 行声明pfun指向 C++ 函数,因为它缺少链接说明符。

因此,第 2 行将 foo 声明为一个 C 函数,它接受一个指向 C++ 函数的指针。

第 5 行尝试使用指向 g(一个 C 函数)的指针(类型不匹配)来调用 foo。

函数名称链接的差异:

让我们看两个不同的文件:

一与extern "c"链接(文件1.cpp):

#include <iostream>
using namespace std;

extern "C"
{
void foo (int a, int b)
{
    cout << "here";
}
}

int main ()
{
    foo (10,20);
    return 0;
}

一个没有extern "c"链接(文件2.cpp):

#include <iostream>
using namespace std;

void foo (int a, int b)
{
    cout << "here";
}

int main ()
{
    foo (10,20);
    return 0;
}

现在编译这两个并检查 objdump。

# g++ file1.cpp -o file1
# objdump -Dx file1

# g++ file2.cpp -o file2
# objdump -Dx file2

使用外部“C”链接,函数不会发生名称修改foo。因此,任何使用它的程序(假设我们用它创建了一个共享库)都可以直接调用 foo (使用诸如dlsym and dlopen)而不考虑任何名称损坏的影响。

0000000000400774 <foo>:
  400774:   55                      push   %rbp
  400775:   48 89 e5                mov    %rsp,%rbp
....
....
  400791:   c9                      leaveq 
  400792:   c3                      retq   

0000000000400793 <main>:
  400793:   55                      push   %rbp
  400794:   48 89 e5                mov    %rsp,%rbp
  400797:   be 14 00 00 00          mov    $0x14,%esi
  40079c:   bf 0a 00 00 00          mov    $0xa,%edi
  4007a1:   e8 ce ff ff ff          callq  400774 <foo>
  4007a6:   b8 00 00 00 00          mov    $0x0,%eax
  4007ab:   c9                      leaveq 

另一方面,当没有extern "C"正在使用,功能:foo被一些预定义的规则(所使用的编译器/链接器已知)破坏,因此应用程序无法直接从中调用它,并将名称指定为foo。但是,您可以使用损坏的名称来调用它(_Z3fooii在这种情况下)如果你愿意的话,但没有人因为明显的原因而使用它。

0000000000400774 <_Z3fooii>:
  400774:   55                      push   %rbp
  400775:   48 89 e5                mov    %rsp,%rbp
 ...
...
  400791:   c9                      leaveq 
  400792:   c3                      retq   

0000000000400793 <main>:
  400793:   55                      push   %rbp
  400794:   48 89 e5                mov    %rsp,%rbp
  400797:   be 14 00 00 00          mov    $0x14,%esi
  40079c:   bf 0a 00 00 00          mov    $0xa,%edi
  4007a1:   e8 ce ff ff ff          callq  400774 <_Z3fooii>
  4007a6:   b8 00 00 00 00          mov    $0x0,%eax
  4007ab:   c9                      leaveq 
  4007ac:   c3                      retq   

这一页 http://www.digitalmars.com/ctg/ctgAsm.html对于这个特定主题也是一本很好的读物。

关于调用约定的一篇很好且解释清楚的文章:http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

名称或类型具有某种语言链接意味着什么? 的相关文章

  • 在 C/C++ 中获得正模数的最快方法

    通常在我的内部循环中 我需要以 环绕 方式索引数组 因此 例如 如果数组大小为 100 并且我的代码要求元素 2 则应该给它元素 98 高级语言 例如 Python 可以简单地使用my array index array size 但由于某
  • 在实体框架拦截器中向 DbScanExpression 添加内部联接

    我正在尝试使用实体框架 CommandTree 拦截器通过 DbContext 向每个查询添加过滤器 为了简单起见 我有两个表 一个称为 User 有两列 UserId 和 EmailAddress 另一个称为 TenantUser 有两列
  • 如何保证对象只有一个线程

    我有以下代码 class Service public void start creates thread which creates window and goes to message loop void stop sends WM C
  • 我如何理解这个 C 类型声明?

    double bar int double double double double 在查看讲座幻灯片时 我发现了留给学生的练习 用简单的英语来说 什么是类型bar在这个 C 声明中 Please帮助我解决这个问题 我什至不知道从哪里开始
  • 何时使用 =default 使析构函数默认?

    尽管对构造函数使用 default 对我来说很清楚 即强制编译器在其他构造函数存在时创建默认构造函数 但我仍然无法理解这两种类型的析构函数之间的区别 那些使用 default 的 那些没有显式定义并由编译器自动生成的 我唯一想到的是 gro
  • EF Core 通过完全替换断开集合导航属性的更新

    使用 EF Core 5 0 我有一个 SPA 页面 可以加载Group实体及其集合Employee来自 API 的实体 var groupToUpdate await context Groups Include g gt g Emplo
  • ASP.NET Web API 客户端 ProgressMessageHandler Post 任务卡在 WinForm 应用程序中

    我在用着HttpClient and ProgressMessageHandler来自MS ASP NET Web API 客户端库 http nuget org packages Microsoft AspNet WebApi Clien
  • 读取 C# 中的默认应用程序设置

    我的自定义网格控件有许多应用程序设置 在用户范围内 其中大部分是颜色设置 我有一个表单 用户可以在其中自定义这些颜色 并且我想添加一个用于恢复默认颜色设置的按钮 如何读取默认设置 例如 我有一个名为的用户设置CellBackgroundCo
  • 类特定的新删除运算符是否必须声明为静态

    标准中是否要求类特定的 new new delete 和 delete 是静态的 我可以让它们成为非静态成员运算符吗 为什么需要它们是静态的 它们被隐式声明为静态 即使您没有键入 static
  • 与 Qt 项目的静态链接

    我有一个在 Visual Studio 2010 Professional 中构建的 Qt 项目 但是 当我运行它 在调试或发布模式下 时 它会要求一些 Qt dll 如果我提供 dll 并将它们放入 System32 中 它就可以工作 但
  • fprintf() 线程安全吗?

    我正在为野人就餐问题的某些变量编写一个 C 解决方案 现在 我创建线程 每个线程都将 FILE 获取到同一个调试文件 在线程内我正在使用 fprintf 进行一些打印 打印的语句不受任何类型的互斥锁等保护 我没有在调试文件中观察到任何交错行
  • 如何在标准 WPF ListView 中启用 UI 虚拟化

    我正在使用 NET 4 5 VS2012 并且我有一个 ListView 看起来像这样
  • ASP.NET MailMessage.BodyEncoding 和 MailMessage.SubjectEncoding 默认值

    很简单的问题 但我在 MSDN 上找不到答案 查找 ASP NET 将用于的默认值 MailMessage BodyEncoding and MailMessage SubjectEncoding 如果你不在代码中设置它们 Thanks F
  • 在 EnvDTE 中调试时捕获 VS 局部变量

    是否可以使用 EnvDTE 进行 vsix Visual Studio 扩展来捕获本地和调试窗口使用的调试数据 或者可以通过其他方法吗 我想创建一个自定义的本地窗口 我们可以修改它以根据需要显示一些较重的内容 而无需为高级用户牺牲原始的本地
  • 使用restsharp序列化对象并将其传递给WebApi而不是序列化列表

    我有一个看起来像的视图模型 public class StoreItemViewModel public Guid ItemId get set public List
  • 新任务中使用的依赖注入服务

    我在需要时使用依赖项注入来访问我的服务 但我现在想要创建一个并发任务 但这会由于依赖项注入对象及其生命周期而导致问题 我读过这篇文章 标题 防止多线程 Link http mehdi me ambient dbcontext in ef6
  • 跨多个域的 ASP.NET 会话

    是否有合适的 NET 解决方案来在多个域上提供持久服务器会话 即 如果该网站的用户在 www site1 com 下登录 他们也将在 www site2 com 下登录 安全是我们正在开发的程序的一个问题 Thanks 它是否需要在会话中
  • 使用taskkill停止Windows服务

    我需要帮助来使用 C 终止 Windows 服务 现在要终止该服务 请使用以下选项 从命令 sc queryex ServiceName 发现后PID服务的 taskkill pid 1234 exemple f 为了便于阅读 但如果您明白
  • 每个数据库多个/单个 *.edmx 文件

    我有一个通过 ADO net 数据服务与数据库交互的项目 数据库很大 近 150 个具有依赖关系的表 该项目几年前开始 当时使用的是数据集 现在我们正在转向实体模型关系 由于我们添加了更多需要使用的表 该模型正在不断增长 这是管理这一切的正
  • xsi:type 属性搞乱了 C# XML 反序列化

    我使用 XSD exe 根据 XML 架构 xsd 文件 自动生成 C 对象 我正在反序列化 OpenCover 输出 但其中一个部分类未正确生成 这是导致异常的行

随机推荐

  • 数据框从宽到长,具有多个变量和 ID R [重复]

    这个问题在这里已经有答案了 我有一个数据框 其中包含参与者对两个文本的判断 假设每个文本都有正确答案和标识符 并且每个文本都被判断多次 set seed 123 wide df data frame participant id LETTE
  • sklearn.* 模块在 0.22 版本中已弃用,并将在 0.24 版本中删除

    我正在将一个软件从 Python 2 7 迁移到 Python 3 出现的一个问题是 sklearn neighbors kde 模块在版本 0 22 中已弃用 并且 将在 0 24 版本中删除 对应的类 函数 应该从 sklearn ne
  • 将计算的 xpage 字段绑定到表单字段

    关于将数据绑定到表单存在很多问题 这很简单 我有一个表单 它使用多个计算字段 这些字段使用 DbLookup 提取数据 以根据用户选择的下拉菜单填充字段 问题是 没有一个计算字段将任何值保存到它所绑定的形式中 表单上保存的唯一数据是手动选择
  • 春季云配置搜索路径

    我正在考虑通过 Spring Cloud Config 实现 12factor 方法来外部化配置 但无法按照我的预期使用 searchPaths 使通配符正常工作 文档http cloud spring io spring cloud co
  • SQL中检查字段是否包含特殊字符

    我们决定使用Nvarchar在某些表中存储一些信息 原因是我们假设我们将有很多特殊字符 因为数据库包含法语和德语数据 提取一些数据后 我们估计完整运行的大小非常巨大 20 TB 现在我们想检查每个表以查找是否找到特殊字符 如果没有 那么我们
  • add_custom_command -- 在重建时更新依赖项列表

    查看上次状态更新 初始条件 代码生成器 生成一组 C 源代码 以一个输入文件作为参数 输入文件可能包含其他输入文件 已经解决了获取输出文件列表 解析输入代码生成文件以获取代码生成输入的完整列表的任务 IE 首次为 add custom co
  • 防止 IIS 通过 ASP.NET 管道提供静态文件

    对我的 css js 图像文件的请求是通过 ASP NET 管道提供的 我认为 IIS 默认情况下会避免这种情况 但我在我的网站上看到了这些请求Application AuthenticateRequest断点 并且不需要实际验证这些请求
  • 在AWS Lambda执行环境上安装第3方库

    我需要为 AWS Lambda 函数安装本机库 使用 RPM 我已经发现这篇博文 https aws amazon com blogs compute nodejs packages in lambda 本机模块部分 但我不知道在哪里编写这
  • 设计WCF数据契约和操作

    我开始设计一个 wcf 服务总线 它现在很小 但会随着我们业务的增长而增长 所以我担心一些日益严重的问题 并尽量不要 YAGNI 太多 这是一个电子商务平台 问题是我对把东西放在哪里犹豫了太多 我将给出一个场景来展示我所有的问题 我们有一个
  • Android:如何使用下载管理器类?

    我想从 url 下载二进制文件 是否可以使用我在这里找到的 Android 下载管理器类下载管理器类 http developer android com reference android app DownloadManager html
  • 在 Clojure 命名空间中排除 java.lang.*

    是否有可能从 Clojure 命名空间中的 java lang 中排除类名 我需要使用像 Byte 和 String 这样的变量 这里 java lang 类名就出现了 也许类似 ns my ns exclude java lang 如果您
  • 何时使用重新编译

    请耐心等待 我无法包含我的 1 000 多行程序 并且描述中有几个问题 所以我正在寻找几种类型的模式 literally just a regular word re search Word arg Varying complex patt
  • 如何重命名大量文件

    我有一个包含这样的文件的目录 a JPG b JPG c JPG 我想做这样的事情 git mv a JPG a jpg 我尝试使用 xargs 和其他工具 但似乎没有任何效果 该解决方案的核心是使用一种工具 方法来自动执行批量重命名 您可
  • 将knockout.js 与django 表单一起使用?

    我希望向我的客户端代码添加一些结构 并且一直在阅读knockout js 我一直在阅读文档并有一个简单的问题要问 因为淘汰赛要求用户添加data bindhtml 元素的属性 它的最佳使用方式是什么django表格 因为目前我正在使用 fo
  • jmeter http请求的每个线程的唯一ID

    我的 jmeter 测试发出一个包含唯一 ID 的 http 请求 http myserver com uniqueId 我想为每个线程设置基数 比如 35000 和增量 例如我的 id 是 35001 35002 35003 http m
  • 类的指针与非指针成员

    我的问题是 假设我们有两个类 A 和 B 我想在 A 类中有一个 B 的对象 我应该使用 class A public A A B b or class A public A A B b 据我所知 在第一种情况下 我可以初始化对象 b us
  • C# - 带种子的随机数

    我有这个代码 var rand new Random 0 for int i 0 i lt 100 i Console WriteLine rand Next 0 100 程序应该给我相同数字的 100 倍 因为种子是相同的 但它给出了不同
  • 如何仅打印 hexdump 中的十六进制值而不显示行号或 ASCII 表? [复制]

    这个问题在这里已经有答案了 下列的在 UNIX shell 脚本中将十进制转换为十六进制 https stackoverflow com questions 378829 convert decimal to hexadecimal in
  • 串口通信初始化

    目前我们正在尝试创建一个串行通信接口 以便能够与微处理器进行通信 事实上 一切都很好 几乎 为了能够与我们的控制器通信 我们需要与其同步 为此 我们编写一个字符串 0 SY 13 然后控制器应该回复 0 SY F5 接受同步请求 为此 我们
  • 名称或类型具有某种语言链接意味着什么?

    根据 c ANSI ISO IEC 14882 2003 第 127 页 联动规格嵌套 当链接规范嵌套时 最里面的规范决定语言 链接规范不建立范围 链接规范仅应出现在名称空间范围内 3 3 在链接规范中 指定的语言链接适用于声明引入的所有函