iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >C#中方法重载实例分析
  • 255
分享到

C#中方法重载实例分析

2023-07-02 10:07:17 255人浏览 薄情痞子
摘要

这篇文章主要介绍了C#中方法重载实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C#中方法重载实例分析文章都会有所收获,下面我们一起来看看吧。最近在看 c++ 的方法重载,我就在想 C# 中的重载底层是怎

这篇文章主要介绍了C#中方法重载实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C#中方法重载实例分析文章都会有所收获,下面我们一起来看看吧。

最近在看 c++ 的方法重载,我就在想 C# 中的重载底层是怎么玩的,很多朋友应该知道 C 是不支持重载的,比如下面的代码就会报错。

#include <stdio.h>int say() {return 1;}int say(int i) {return i;}int main(){say(10);return 0;}

C#中方法重载实例分析

从错误信息看,它说 say 方法已经存在了,尴尬。。。

一:为什么 C 不支持

要想寻找答案,需要了解一点点底层知识,那就是编译器在编译 C 方法时会将函数名作为符号添加到符号表中,这个符号表 就是call到say方法字节码中间的一个载体,画个图大概就是这样。

C#中方法重载实例分析

简而言之,call 先跳转到符号表, 然后再 jmp 到 say 方法,问题就出现在这里,符号表是一种类字典结构,是不可以出现符号相同的情况。对了,在 windbg 中我们可以用 x 命令去搜索这些符号,

为了论证我的说法,可以在汇编层面给大家验证下,修改代码如下:

#include <stdio.h>int say(int i) {return i;}int main(){say(10);return 0;}

接下来再看下汇编。

--------------- say(10) -----------00C41771  push        0Ah  00C41773  call        _say (0C412ADh)  --------------- 符号表 -----------00C412AD  jmp         say (0C417B0h)  --------------- say body -----------00C417B0  push        ebp  00C417B1  mov         ebp,esp  00C417B3  sub         esp,0C0h  00C417B9  push        ebx  00C417BA  push        esi  00C417BB  push        edi  00C417BC  mov         edi,ebp  00C417BE  xor         ecx,ecx  00C417C0  mov         eax,0CCCCCCCCh  00C417C5  rep stos    dWord ptr es:[edi]  00C417C7  mov         ecx,offset _2440747F_ConsoleApplication6@c (0C4C008h)  ...

知道了原理后,我们再看看 C++ 是如何在符号表上实现唯一性突破。

二:C++ 符号表突破

为了方便讲述,我们先上一段 C++ 方法重载的代码。

using namespace std;class Person{public:void sayhello(int i) {cout << i << endl;}void sayhello(const char* c) {cout << c << endl;}};int main(int arGC){Person person;person.sayhello(10);person.sayhello("hello world");}

按理说 sayhello 有多个,肯定是无法突破的,带着好奇心我们看下它的反汇编代码。

----------     person.sayhello(10);  ----------------003B2E5F  push        0Ah  003B2E61  lea         ecx,[person]  003B2E64  call        Person::sayhello (03B13A2h) ------------  person.sayhello("hello world"); ----------------003B2E69  push        offset string "hello world" (03B9C2Ch)  003B2E6E  lea         ecx,[person]  003B2E71  call        Person::sayhello (03B1302h)

从汇编代码看, 调的都是 Person::sayhello 这个符号,奇怪的是他们属于不同的地址: 03B13A2h03B1302h,这就太奇怪了,哈哈,字典类符号表肯定是没有问题的,问题是 Visual Studio 20222 的反汇编窗口在调试时做了一些内部转换,算是蒙蔽了我们双眼吧,

真是可气!!!居然运行时汇编代码都还不够彻底,那现在我们怎么继续挖呢? 可以用 IDA 去看这个程序的静态反汇编代码,截图如下:

C#中方法重载实例分析

从代码上的注释可以清楚的看到,原来:

  • Person::sayhello(int) 变成了 j_?sayhello@Person@@QAEXH@Z

  • Person::sayhello(char const *) 变成了 j_?sayhello@Person@@QAEXPBD@Z

到这里终于搞清楚了,原来 C++ 为了支持方法重载,将方法名做了重新编码,这样确实可以突破符号表的唯一性限制。

三:C#如何实现突破

我们都知道 C# 的底层 CLR 是由 C++ 写的,所以大概率玩法都是一样,接下来上一段代码:

    internal class Program    {        static void Main(string[] args)        {//故意做一次重复            Say(10);            Say("hello world");            Say(10);            Say("hello world");            Console.ReadLine();        }        static void Say(int i)        {            Console.WriteLine(i);        }        static void Say(string s)        {            Console.WriteLine(s);        }    }

由于 C# 的方法是由 JIT 在运行时动态编译的,并且首次编译方法会先跳转到 JIT 的桩地址,所以断点必须下在第二次调用 Say(10) 处才能看到方法的符号地址,汇编代码如下:

 -----------Say(10);-----------00007FFB82134DFC  mov         ecx,0Ah  00007FFB82134E01  call        Method stub for: ConsoleApp1.Program.Say(Int32) (07FFB81F6F118h)  00007FFB82134E06  nop  -----------Say("hello world");-----------00007FFB82134E07  mov         rcx,qword ptr [1A8C65E8h]  00007FFB82134E0F  call        Method stub for: ConsoleApp1.Program.Say(System.String) (07FFB81F6F120h)  00007FFB82134E14  nop

从输出信息看,同样也是两个符号表地址,然后由符号表地址 jmp 到最后的方法体。

-----------Say(10);-----------00007FFB82134E01  call        Method stub for: ConsoleApp1.Program.Say(Int32) (07FFB81F6F118h)  -----------符号表-----------00007FFB81F6F118  jmp         ConsoleApp1.Program.Say(Int32) (07FFB82134F10h)  -----------Say body -----------00007FFB82134F10  push        rbp  00007FFB82134F11  push        rdi  00007FFB82134F12  push        rsi  00007FFB82134F13  sub         rsp,20h  00007FFB82134F17  mov         rbp,rsp  00007FFB82134F1A  mov         dword ptr [rbp+40h],ecx  00007FFB82134F1D  cmp         dword ptr [7FFB82036B80h],0  00007FFB82134F24  je          ConsoleApp1.Program.Say(Int32)+01Bh (07FFB82134F2Bh)  00007FFB82134F26  call        00007FFBE1C2CC40

关于“C#中方法重载实例分析”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“C#中方法重载实例分析”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网精选频道。

--结束END--

本文标题: C#中方法重载实例分析

本文链接: https://www.lsjlt.com/news/341104.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • c#程序自启动怎么设置
    c# 程序的自启动方法有三种:注册表:在指定注册表项下创建新值,并将其设置为程序可执行文件路径。任务计划程序:创建一个新任务,并在触发器和动作部分分别指定登录时或特定时间触发,以及启动程...
    99+
    2024-05-14
    c#
  • c#怎么调用dll文件
    可在 c# 中轻松调用 dll 文件:引用 dll(使用 dllimport 特性)定义与 dll 函数签名匹配的函数原型调用 dll 函数(如同 c# 函数)附加技巧:使用 chars...
    99+
    2024-05-14
    c#
  • 如何构建 Golang RESTful API,并实现 CRUD 操作?
    通过创建 golang 项目并安装必要的包,我们可以构建一个功能齐全的 restful api。它使用 mysql 数据库进行 crud 操作:1. 创建和连接数据库;2. 定义数据结构...
    99+
    2024-05-14
    go crud mysql git golang
  • c#怎么添加类文件
    在c#中添加类文件的步骤:1. 创建新项目,2. 添加新类,3. 为类添加代码,4. 在另一个类中引用新类。using语句引用类文件所在的命名空间;new运算符创建类的新实例;点运算符访...
    99+
    2024-05-14
    c#
  • 使用 C++ 构建高性能服务器架构的最佳实践
    遵循 c++++ 中构建高性能服务器架构的最佳实践可以创建可扩展、可靠且可维护的系统:使用线程池以重用线程,提高性能。利用协程减少上下文切换和内存开销,提升性能。通过智能指针和引用计数优...
    99+
    2024-05-14
    c++ 高性能服务器架构 数据访问
  • c#怎么添加字段
    在 c# 中添加字段包括以下步骤:声明字段:在类或结构中使用 字段类型 字段名; 语法声明字段。访问修饰符:用于限制对字段的访问,如 private、public、protected 和...
    99+
    2024-05-14
    c#
  • c#中怎么添加引用
    c# 中添加引用的方法有四种:使用 nuget 包管理器添加软件包。添加项目引用以包含其他项目。手动编辑项目文件 (.csproj) 以添加引用。从编译器命令行使用 /reference...
    99+
    2024-05-14
    c#
  • c#怎么创建文本文件
    在 c# 中创建文本文件的方法包括:创建 filestream 对象以打开或创建文件。使用 streamwriter 写入文本至文件。关闭 streamwriter 对象释放资源。关闭 ...
    99+
    2024-05-14
    c#
  • c#怎么定义属性
    如何在 c# 中定义属性 属性是一种编程构造,它包含一个 get 访问器和一个 set 访问器,允许以一种类属性的方式访问字段。它们提供了一种安全且封装的方式来访问和修改类的内部数据。 ...
    99+
    2024-05-14
    c#
  • 基于 C++ 的服务器架构的安全性考虑因素
    在设计基于 c++++ 的服务器架构时,安全考虑至关重要:使用 std::string 或 std::vector 避免缓冲区溢出。使用正则表达式或库函数验证用户输入。采用输出转义防止跨...
    99+
    2024-05-14
    安全性 关键词: c++ 服务器架构 c++ lsp
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作