PPSSPP代码规范:编码标准和最佳实践

PPSSPP代码规范:编码标准和最佳实践

【免费下载链接】ppsspp A PSP emulator for Android, Windows, Mac and Linux, written in C++. Want to contribute? Join us on Discord at https://discord.gg/5NJB6dD or just send pull requests / issues. For discussion use the forums at forums.ppsspp.org. 【免费下载链接】ppsspp 项目地址: https://gitcode.com/GitHub_Trending/pp/ppsspp

1. 项目背景与规范重要性

PPSSPP作为跨平台的PSP模拟器(支持Android、Windows、macOS和Linux),其代码库采用C++开发,包含超过400个源代码文件,涉及模拟器核心、图形渲染、输入处理等复杂模块。统一的编码规范对确保代码可维护性、降低协作成本至关重要。本文档基于项目现有实践(如.editorconfig配置、头文件宏定义)和行业最佳实践,系统化整理编码标准。

2. 基础编码规范

2.1 文件格式与编码

规范项要求适用范围
字符编码UTF-8(无BOM,除非特殊需求如PSPOskDialog.cpp使用UTF-8-BOM)所有.cpp/.h文件
行尾符LF(Unix风格)所有文本文件
缩进Tab(宽度8空格)除特殊文件外(见2.2)
文件结尾单个空行所有源代码文件

2.2 特殊文件类型例外

# .editorconfig核心配置示例
[*]
indent_style = tab
charset = utf-8
insert_final_newline = true

[*.{py,yml}]
indent_style = space
indent_size = 2

[libretro/**.{cpp,h}]
indent_style = space
indent_size = 3

3. 命名约定

3.1 标识符命名规则

类型风格示例
类/结构体PascalCaseGraphicsContext, CoreState
函数/方法PascalCaseCore_Resume(), BreakReasonToString()
变量/参数camelCaseframeSkipCount, relatedAddress
常量UPPER_SNAKE_CASEMAX_PATH, DEFAULT_FRAME_RATE
枚举值PascalCaseCORE_RUNNING_CPU, BreakReason::DebugBreak
宏定义UPPER_SNAKE_CASEDISALLOW_COPY_AND_ASSIGN, ARRAY_SIZE

3.2 命名示例对比

// 正确:类名PascalCase,成员变量camelCase
class FrameTiming {
private:
    int frameCount;
    double lastFrameTime;
};

// 正确:枚举值PascalCase
enum class DisplayFramerateMode {
    Auto,
    Fixed60,
    Fixed30
};

// 错误:函数名使用下划线
void frame_timing_update(); // 应改为FrameTimingUpdate()

4. 代码格式

4.1 括号与换行

采用K&R风格(左括号不换行):

// 正确
if (coreState == CORE_RUNNING_CPU) {
    ProcessFrame();
} else {
    HandlePause();
}

// 错误:左括号换行
if (coreState == CORE_RUNNING_CPU)
{
    ProcessFrame();
}

4.2 空格使用规范

  • 关键字后加空格:if (condition), for (int i=0;...)
  • 运算符两侧加空格:a = b + c, x == y
  • 逗号后加空格:function(a, b, c)
  • 指针/引用符号靠近类型:int* ptr(而非int *ptr

4.3 注释规范

// 单行注释:句首大写,后接空格(用于临时说明)

/*
 * 多行块注释:用于函数/类文档
 * 描述:初始化图形上下文
 * 参数:ctx - 指向GraphicsContext的指针
 */
void Core_SetGraphicsContext(GraphicsContext *ctx);

// TODO: 待办事项需注明责任人
// TODO(hrydgard): 优化纹理加载性能

5. 类型与宏定义

5.1 基础类型使用

优先使用C++标准类型及项目自定义类型:

#include "CommonTypes.h" // 项目基础类型定义

// 正确:使用明确宽度类型
u8  byteValue;  // 无符号8位
s32 intValue;   // 有符号32位
f32 floatValue; // 单精度浮点

// 错误:使用模糊原生类型
int count;      // 应改为s32或u32

5.2 禁用复制与赋值宏

使用DISALLOW_COPY_AND_ASSIGN防止对象复制:

class EmulatorInstance {
private:
    DISALLOW_COPY_AND_ASSIGN(EmulatorInstance); // 禁止复制构造与赋值
public:
    EmulatorInstance() = default;
    // ...
};

5.3 枚举类位运算支持

使用ENUM_CLASS_BITOPS启用枚举类位运算:

enum class LogOutput {
    Console = 1 << 0,
    File    = 1 << 1,
    Network = 1 << 2
};
ENUM_CLASS_BITOPS(LogOutput); // 启用|=, &=等运算符

// 使用示例
LogOutput output = LogOutput::Console | LogOutput::File;

6. 类与函数设计

6.1 类成员顺序

按访问权限排序:publicprotectedprivate,同类成员按声明顺序排序:

class Core {
public:
    void Run();
    void Pause();
protected:
    virtual void UpdateState();
private:
    CoreState currentState;
    u32 frameCounter;
};

6.2 函数设计原则

  • 单一职责:函数应完成一个明确任务(不超过200行)
  • 参数数量:优先使用结构体封装多参数(超过4个时)
  • 返回类型:避免返回复杂对象的原始指针(优先使用智能指针)
// 推荐:使用结构体封装多参数
struct FrameParams {
    u32 width;
    u32 height;
    bool vsync;
};

void RenderFrame(const FrameParams& params);

7. 错误处理与调试

7.1 断言使用场景

  • 开发阶段:使用DEBUG_ASSERT验证内部状态
  • 运行时检查:对用户输入使用显式错误返回
#include "Common/Common.h"

void LoadTexture(const std::string& path) {
    DEBUG_ASSERT(!path.empty()); // 开发时检查前置条件
    if (path.empty()) {
        ERROR_LOG(Load, "Invalid texture path");
        return;
    }
    // ...加载逻辑
}

7.2 日志记录规范

使用项目日志宏按模块分类:

ERROR_LOG(GPU, "Failed to compile shader: %s", shaderName.c_str());
WARN_LOG(Audio, "Low latency mode not supported");
INFO_LOG(UI, "Theme loaded: %s", themePath.c_str());

8. 性能优化准则

8.1 内存管理

  • 优先使用栈内存(std::array替代new[]
  • 大内存块使用MemArena(项目内存池)
// 示例:使用内存池分配临时缓冲区
MemArena arena;
u8* buffer = arena.Alloc(4096); // 自动释放,无需手动delete

8.2 循环优化

  • 减少循环内计算(提取不变式)
  • 使用constconstexpr优化编译期计算
// 优化前
for (int i=0; i<textures.size(); i++) {
    if (textures[i].width > screenWidth / 2) { // 重复计算screenWidth/2
        ResizeTexture(&textures[i]);
    }
}

// 优化后
const int maxWidth = screenWidth / 2;
for (const auto& tex : textures) { // 使用范围for循环
    if (tex.width > maxWidth) {
        ResizeTexture(&tex);
    }
}

9. 跨平台兼容性

9.1 条件编译规范

使用项目预定义宏隔离平台代码:

#if PPSSPP_PLATFORM(WINDOWS)
    #include <windows.h>
#elif PPSSPP_PLATFORM(LINUX)
    #include <unistd.h>
#elif PPSSPP_PLATFORM(ANDROID)
    #include <android/log.h>
#endif

9.2 路径处理

使用Path类(Common/File/Path.h)处理跨平台路径:

Path romPath = Path::FromUTF8(gamePath);
if (romPath.Exists()) {
    LoadROM(romPath);
}

10. 代码审查与质量保障

10.1 审查重点清单

审查维度检查项
功能正确性边界条件处理、错误码检查
性能影响算法复杂度、内存分配频率
可读性命名清晰度、注释充分性
兼容性跨平台API使用、C++17特性合规性

10.2 持续集成要求

  • 提交前通过本地编译(cmake && make
  • 单元测试覆盖率≥70%(unittest/目录)
  • 静态分析无警告(cppcheck/clang-tidy

mermaid

11. 总结与最佳实践清单

11.1 核心规范速查表

  1. 命名:PascalCase(类/枚举)、camelCase(变量/函数)、UPPER_SNAKE_CASE(宏)
  2. 格式:Tab缩进、UTF-8编码、K&R括号风格
  3. 安全:禁用new/delete(使用内存池)、检查所有指针有效性
  4. 性能:避免循环内字符串拼接、优先使用栈分配

11.2 推荐学习资源

  • 项目源码:Common/目录(基础组件)、Core/HLE/(HLE实现)
  • 开发文档:PPSSPP开发者 Wiki(需替换为国内镜像链接)
  • 工具链:CMake 3.16+、Clang 10+、Android NDK 21+

通过遵循以上规范,PPSSPP代码将保持一致性、可维护性和高性能,同时降低协作冲突。所有贡献者应在提交代码前运行clang-format(项目根目录执行./format.sh)确保格式统一。

【免费下载链接】ppsspp A PSP emulator for Android, Windows, Mac and Linux, written in C++. Want to contribute? Join us on Discord at https://discord.gg/5NJB6dD or just send pull requests / issues. For discussion use the forums at forums.ppsspp.org. 【免费下载链接】ppsspp 项目地址: https://gitcode.com/GitHub_Trending/pp/ppsspp

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值