聊一聊CLR中的typedef是怎么玩的

一:背景

在 CLR 源码中,我们会看到很多关于 typedef 的定义,比如下面这样:.

// Callback function type used by DacStreamManager to coordinate
// amount of available memory between multiple streamable data
// structures (e.g. DacEENamesStreamable)
typedef bool (*Reserve_Fnptr)(DWORD size, void * writeState);

typedef BOOL (*NTQUERYSYSTEMINFORMATION)(SYSTEM_INFORMATION_CLASS SystemInformationClass,
                                         PVOID SystemInformation,
                                         ULONG SystemInformationLength,
                                         PULONG ReturnLength);

typedef struct _HashInstanceKey {
    TADDR addr;
    DAC_INSTANCE* instance;
} HashInstanceKey;

typedef TokenHashMap<EEClass> EEClassToTypeRefMap;
typedef TokenHashMap<MethodTable> MTToTypeRefMap;

如果你不了解 C 的话又是一阵头晕,那 typedef 到底能给我们带来什么好处呢?直白的说,它可以给某一些类型定义别名,比如结构体,变量,函数指针 等等,类型越复杂好处越大,接下来我们举两个例子说明一下。

二:typedef 的简单用法

  1. 使用 typedef 定义函数指针

在不用 typedef 的前提下,我们看看原生方式的 函数指针 有多么复杂,参考代码如下:

#include <iostream>

//函数指针
int (*ptrAddFunc)(int a, int b);

int Add(int a, int b) { return a + b; }

int main()
{
 int (*ptrAddFunc1)(int a, int b) = Add;
 int (*ptrAddFunc2)(int a, int b) = Add;

 int sum1 = ptrAddFunc1(10, 20);
 int sum2 = ptrAddFunc1(100, 200);

 printf("sum1=%d, sum2=%d", sum1, sum2);
}

如果用 typedef 来统一替换别名会怎么样呢?试一试就知道了哈,参考代码如下:

#include <iostream>

//函数指针
typedef int (*ptrAddFunc)(int a, int b);

int Add(int a, int b) { return a + b; }

int main()
{
 ptrAddFunc func1 = Add;
 ptrAddFunc func2 = Add;

 int sum1 = func1(10, 20);
 int sum2 = func2(100, 200);

 printf("sum1=%d, sum2=%d", sum1, sum2);
}

是不是找到了写 C# 的感觉了哈,太方便了。

  1. 建立一套自己的类型系统

熟悉 C# 的朋友应该了解其有一套基元类型如:Int32, Int64,Float, Double,那如何将它带到 C 的环境下呢?这就需要用 typedef 啦,参考如下代码:

#include <iostream>

typedef long long Int64;
typedef int Int32;
typedef float Float;
typedef double Double;

int Add(int a, int b) { return a + b; }

int main()
{
 Int32 i32 = 10;
 Int64 i64 = 11;

 size_t s1 = sizeof(Int32);
 size_t s2 = sizeof(Int64);

 printf("output:sizeof_int=%zu,sizeof_long=%zu,i32=%d,i64=%d", s1, s2, i32, i64);
}

output:sizeof_int=4,sizeof_long=8,i32=10,i64=11

三:typedef 和 define 的区别

仔细想想,其实它们基因是不同的,一个是占位符,一个是取别名,两个不同用途的东西自然就会在多个场景下有着不一样的展示, 比如在指针上就有区别。

#include <iostream>

#define ptr1 char*
typedef char* ptr2;

int main()
{
 ptr1 p1, p2;
 ptr2 p10, p20;

 printf("output: p1=%zu, p2=%zu,p10=%zu, p20=%zu", sizeof(p1),sizeof(p2),sizeof(p10),sizeof(p20));
}

output: p1=4, p2=1,p10=4, p20=4

从size大小可判断,4 表示一个32bit的指针单元,那 1 是什么东西呢?我们截图看一下:

聊一聊CLR中的typedef是怎么玩的

 

可以看出它是一个 char 类型,这就是它们俩不一样,当然这是编译器层面做出的选择,大体上就聊这么多吧,希望对你有帮助。