C#与C对比学习指南:从语法差异到实战应用

1次阅读
没有评论

共计 1723 个字符,预计需要花费 5 分钟才能阅读完成。

image.webp

关键差异速查表

特性 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# 与 C 对比学习指南:从语法差异到实战应用

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)
  • 使用 refout关键字匹配 C 的指针参数:
    [DllImport("lib")]
    static extern void ModifyStruct(ref MyStruct s);

P/Invoke 规范

  1. 字符集必须显式指定:
    [DllImport("lib", CharSet = CharSet.Ansi)]
  2. 回调函数需保持引用防止 GC 回收:
    GCHandle.Alloc(callbackDelegate);

异步编程差异

  • C 的异步通常基于回调函数
  • C# 的 async/await 会生成状态机,注意:
  • 避免 async void(除事件处理器)
  • Task.Run 不适用于 CPU 密集型操作

延伸思考

  1. 混合编程场景
  2. 需要极致性能的热点代码
  3. 复用现有 C /C++ 库
  4. 硬件直接操作需求

  5. GC 影响评估

  6. 实时系统应避免频繁 GC:
    • 使用对象池
    • 控制大对象分配
    • 考虑手动内存管理区域
  7. 测量 GC 暂停时间:
    GC.TryStartNoGCRegion(1000000);
    // 关键代码
    GC.EndNoGCRegion();

结语

从 C 切换到 C# 不仅是语法的转变,更是编程范式的迁移。建议初期重点理解:
– 面向对象设计思维
– 托管内存的工作机制
– .NET 基础类库的组织方式
遇到性能瓶颈时,合理使用 unsafe 代码和 P /Invoke,但切记『过早优化是万恶之源』。

正文完
 0
评论(没有评论)