C语言实现C++的封装特性(MISRA C 3306)

文章介绍了MISRAC2012标准中的3306规则,该规则提倡使用不透明指针来封装结构体,以隐藏实现细节,提高代码的可维护性和安全性。通过示例展示了如何在C语言中实现这种封装,包括在头文件中声明不透明指针类型和公共接口,在实现文件中定义结构体和接口函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

今天在检查代码QAC时发现一个之前未见过的rule:3306,提示The implementation of the struce/union type should be hide,当时并不知道什么意思,回来查资料有点像用C语言实现C++的封装特性。

Misra C

MISRA C:2012 standard中对3306做出以下解释:

The typedef name of a structure shall be a unique identifier and shall be used only in the definition of the structure. The contents of any structure shall not be accessed directly, but only through functions.

我的理解是MISRA C建议结构体的访问最好使用不透明的指针,这有助于确保结构的实现细节对程序的其他部分隐藏,从而提高可维护性并降低错误风险。

我们通常会将结构体的定义和声明分别放在不同的头文件中。这样可以确保只有实现该结构体的源文件才能访问结构体的实际定义,而其他源文件只能使用结构体的指针。

例子

以下是一个示例,演示如何使用不透明的结构体指针来隐藏结构体的实现细节:

首先,在头文件中声明结构体类型和一组公共接口函数,如下所示:

// employee.h

// 不透明的指针类型,用于表示 Employee 结构体
typedef struct Employee* EmployeePtr;

// 公共接口函数,用于创建和销毁 Employee 对象
EmployeePtr createEmployee(const char* name, const char* hireDate, double salary);
void destroyEmployee(EmployeePtr employee);

// 公共接口函数,用于获取和设置 Employee 对象的属性
const char* getEmployeeName(EmployeePtr employee);
const char* getEmployeeHireDate(EmployeePtr employee);
double getEmployeeSalary(EmployeePtr employee);
void setEmployeeSalary(EmployeePtr employee, double salary);

然后,在实现文件中定义结构体类型和公共接口函数的实现,如下所示:

// employee.c

#include "employee.h"
#include <string.h>
#include <stdlib.h>

// Employee 结构体的实际定义
struct Employee {
    char name[256];
    char hireDate[256];
    double salary;
};

// 创建 Employee 对象并返回指针
EmployeePtr createEmployee(const char* name, const char* hireDate, double salary) {
    // 分配内存以存储 Employee 结构体
    EmployeePtr employee = (EmployeePtr) malloc(sizeof(struct Employee));
    // 将参数复制到结构体中
    strncpy(employee->name, name, sizeof(employee->name));
    strncpy(employee->hireDate, hireDate, sizeof(employee->hireDate));
    employee->salary = salary;
    // 返回指针
    return employee;
}

// 销毁 Employee 对象
void destroyEmployee(EmployeePtr employee) {
    // 释放内存
    free(employee);
}

// 获取 Employee 的姓名
const char* getEmployeeName(EmployeePtr employee) {
    return employee->name;
}

// 获取 Employee 的雇佣日期
const char* getEmployeeHireDate(EmployeePtr employee) {
    return employee->hireDate;
}

// 获取 Employee 的薪资
double getEmployeeSalary(EmployeePtr employee) {
    return employee->salary;
}

// 设置 Employee 的薪资
void setEmployeeSalary(EmployeePtr employee, double salary) {
    employee->salary = salary;
}

在上述示例中,Employee 结构体的实际定义和实现被隐藏在实现文件中,只有通过使用不透明的指针类型(EmployeePtr)才能访问结构体的公共接口函数。这有助于确保只有实现文件能够直接访问 Employee 结构体的实现细节,并提高了代码的可维护性和可重用性。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值