共计 1723 个字符,预计需要花费 5 分钟才能阅读完成。
关键差异速查表
| 特性 | C 语言 | C# 语言 |
|---|---|---|
| 内存管理 | 手动 malloc/free | 自动垃圾回收(GC) |
| 代码组织 | 头文件 (.h) 包含声明 | 命名空间 (namespace) 封装 |
| 指针操作 | 原生指针广泛使用 | 需 unsafe 上下文,推荐用引用 |
| 字符串 | char 数组 +null 终止符 | System.String 不可变对象 |
| 编译方式 | 直接编译为机器码 | 编译为 IL+JIT 即时编译 |
| 多线程 | 依赖 OS API(pthread 等) | Thread 类 +async/await 语法糖 |
典型场景对比实现
1. 链表数据结构实现
C 语言版本:
struct Node {
int data;
struct Node* next; // 必须显式使用指针
};
void Insert(struct Node** head, int data) {struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = *head;
*head = newNode; // 需要二级指针修改头节点
}

C# 版本:
class Node {public int Data { get; set;} // 属性代替公共字段
public Node Next {get; set;} // 自动内存管理
}
class LinkedList {
private Node _head;
public void Insert(int data) {
_head = new Node { // 对象初始化语法
Data = data,
Next = _head
};
}
}
2. 多线程同步案例
C 语言(pthread):
pthread_mutex_t lock;
int counter = 0;
void* ThreadProc(void* arg) {pthread_mutex_lock(&lock);
counter++; // 必须手动加锁
pthread_mutex_unlock(&lock);
return NULL;
}
C# 版本:
private static readonly object _lockObj = new object();
private static int _counter;
async Task ThreadProc() {await Task.Run(() => {lock (_lockObj) { // 语法糖简化同步
_counter++;
}
});
}
3. 原生代码互操作
C 导出函数:
__declspec(dllexport)
int AddNumbers(int a, int b) {return a + b;}
C# 调用(P/Invoke):
[DllImport("NativeLib.dll")]
static extern int AddNumbers(int a, int b);
// 调用示例
var sum = AddNumbers(3, 5); // 自动类型 marshal
避坑指南
值类型 / 引用类型陷阱
- 在 P /Invoke 调用时,结构体默认按值传递(C# 中 struct)
- 使用
ref或out关键字匹配 C 的指针参数:[DllImport("lib")] static extern void ModifyStruct(ref MyStruct s);
P/Invoke 规范
- 字符集必须显式指定:
[DllImport("lib", CharSet = CharSet.Ansi)] - 回调函数需保持引用防止 GC 回收:
GCHandle.Alloc(callbackDelegate);
异步编程差异
- C 的异步通常基于回调函数
- C# 的 async/await 会生成状态机,注意:
- 避免 async void(除事件处理器)
- Task.Run 不适用于 CPU 密集型操作
延伸思考
- 混合编程场景:
- 需要极致性能的热点代码
- 复用现有 C /C++ 库
-
硬件直接操作需求
-
GC 影响评估:
- 实时系统应避免频繁 GC:
- 使用对象池
- 控制大对象分配
- 考虑手动内存管理区域
- 测量 GC 暂停时间:
GC.TryStartNoGCRegion(1000000); // 关键代码 GC.EndNoGCRegion();
结语
从 C 切换到 C# 不仅是语法的转变,更是编程范式的迁移。建议初期重点理解:
– 面向对象设计思维
– 托管内存的工作机制
– .NET 基础类库的组织方式
遇到性能瓶颈时,合理使用 unsafe 代码和 P /Invoke,但切记『过早优化是万恶之源』。
正文完
