├── .clang-format ├── .gitignore ├── README.md ├── checker ├── bin │ └── MCUX-SDK-CodingStyleChecker.exe ├── env │ ├── do_pack_by_pyinstaller.bat │ ├── do_setup_by_pip.bat │ └── pyinstaller_pack_f.spec ├── gui │ └── MCUX-SDK-CodingStyleChecker.ui ├── img │ ├── MCUX-SDK-CodingStyleChecker.PNG │ └── MCUX-SDK-CodingStyleChecker.ico ├── log │ └── _temp.txt ├── src │ ├── checkerWin.py │ ├── main.py │ └── uilang.py └── test │ ├── test_gbk.c │ ├── test_utf8.c │ ├── test_utf8.h │ └── 中文 │ └── test_utf8.h ├── coding_style.md ├── images └── build_v0.5.PNG ├── template.c └── template.h /.clang-format: -------------------------------------------------------------------------------- 1 | BreakBeforeBraces: Custom 2 | BraceWrapping: 3 | AfterEnum : true 4 | AfterStruct : true 5 | SplitEmptyFunction : true 6 | AfterClass : true 7 | AfterControlStatement : true 8 | AfterFunction : true 9 | AfterNamespace : true 10 | AfterObjCDeclaration : true 11 | AfterUnion : true 12 | AfterExternBlock : false 13 | BeforeCatch : true 14 | BeforeElse : true 15 | SortIncludes : false 16 | AlignConsecutiveAssignments : true 17 | AlignConsecutiveDeclarations : false 18 | AlignTrailingComments : true 19 | AllowAllParametersOfDeclarationOnNextLine : true 20 | AllowShortBlocksOnASingleLine : false 21 | AllowShortFunctionsOnASingleLine : "None" 22 | AllowShortIfStatementsOnASingleLine : false 23 | AllowShortLoopsOnASingleLine : false 24 | AlwaysBreakBeforeMultilineStrings : true 25 | BasedOnStyle : "Google" 26 | BinPackParameters : false 27 | BreakBeforeBinaryOperators : false 28 | BreakBeforeTernaryOperators : false 29 | ColumnLimit : 120 30 | ContinuationIndentWidth : 4 31 | DerivePointerAlignment : false 32 | DisableFormat : false 33 | IndentCaseLabels : true 34 | IndentWrappedFunctionNames : false 35 | IndentWidth : 4 36 | Language : "Cpp" 37 | MaxEmptyLinesToKeep : 1 38 | PointerBindsToType : false 39 | SpaceBeforeAssignmentOperators : true 40 | SpaceBeforeParens : "ControlStatements" 41 | SpacesBeforeTrailingComments : 1 42 | SpacesInCStyleCastParentheses : false 43 | SpacesInParentheses : false 44 | Standard : "Cpp03" 45 | TabWidth : 1 46 | UseTab : "Never" 47 | 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE! Don't add files that are generated in specific 3 | # subdirectories here. Add them in the ".gitignore" file 4 | # in that subdirectory instead. 5 | # 6 | # NOTE! Please use 'git ls-files -i --exclude-standard' 7 | # command after changing this file, to see if there are 8 | # any tracked files which get ignored after the change. 9 | # 10 | # Normal rules 11 | # 12 | *.fbp.bak 13 | 14 | /checker/.idea 15 | /checker/doc/ 16 | /bin/*.json 17 | 18 | # Python bytecode 19 | *.pyc 20 | __pycache__ 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MCUXpresso SDK Coding Style 2 | 3 | ### 1.代码风格 4 | 5 | > * 风格细则:https://github.com/JayHeng/MCU-CodingStyleChecker/blob/master/coding_style.md 6 | 7 | ### 2.代码模板 8 | 9 | > * 头文件模板:https://github.com/JayHeng/MCU-CodingStyleChecker/blob/master/template.h 10 | > * 源文件模板:https://github.com/JayHeng/MCU-CodingStyleChecker/blob/master/template.c 11 | 12 | ### 3.检查工具 13 | 14 |   MCUXpresso SDK Coding Style Checker 是恩智浦 SDK 驱动 C 代码风格配套检查工具,其功能类似于 [Linux](https://github.com/torvalds/linux) 下的 scripts/checkpatch.pl 脚本和谷歌开源项目 [styleguide](https://github.com/google/styleguide) 下的 cpplint/cpplint.py 脚本,只不过提供的规范检查没有这两个工具丰富,是一个轻量级的工具。此外本工具基于 PyQt5 做了一个简洁的 GUI,更适合普通 MCU 开发者使用。 15 | 16 | > * 工具:\MCU-CodingStyleChecker\checker\bin\MCUX-SDK-CodingStyleChecker.exe 17 | 18 |   MCUXpresso SDK Coding Style Checker 主要功能如下: 19 | 20 | > * 支持选择单文件或整个文件夹去检查 21 | > * 自动识别 .c/.h 后缀文件,但要保证文件是 UTF-8 或 ASCII 编码(即不能包含非英文字符) 22 | > * 能够显示检查结果的统计信息(总代码行,错误行,错误率) 23 | > * 支持检查结果Log的保存 24 | > * 支持检查五种通用注释头(Definitions/Variables/Prototypes/Code/API) 25 | > * 支持检查全局变量的命名规范(在Variables注释头下) - coding_style.md | rule 1.1 26 | > * 支持检查宏定义的命名规范(在Definitions注释头下) - coding_style.md | rule 1.2 27 | > * 支持检查枚举定义的命名规范(在Definitions注释头下) - coding_style.md | rule 1.3 28 | > * 支持检查结构体定义的命名规范(在Definitions注释头下) - coding_style.md | rule 1.4 29 | > * 支持检查函数的命名规范(在Code注释头下) - coding_style.md | rule 1.5 30 | > * 支持检查头文件保护宏 - coding_style.md | rule 2.7 31 | 32 |   To-Do List: 33 | 34 | > * 集成clang-format,检测开始前自动先做一次格式化 35 | > * 支持 coding_style.md里的 rule 2.x 36 | > * 支持检查规则设置(使能/不使能,命名风格自选择) 37 | > * 支持过滤文件/文件夹规则设置 38 | > * 支持检查的实时进度条显示 39 | 40 | ![](./images/build_v0.5.PNG) 41 | 42 | -------------------------------------------------------------------------------- /checker/bin/MCUX-SDK-CodingStyleChecker.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JayHeng/MCU-CodingStyleChecker/f49469a977562b79c6c818571ba6d1275bb70f82/checker/bin/MCUX-SDK-CodingStyleChecker.exe -------------------------------------------------------------------------------- /checker/env/do_pack_by_pyinstaller.bat: -------------------------------------------------------------------------------- 1 | pyinstaller.exe pyinstaller_pack_f.spec 2 | copy .\dist\MCUX-SDK-CodingStyleChecker.exe ..\bin 3 | rd /q /s .\build 4 | rd /q /s .\dist -------------------------------------------------------------------------------- /checker/env/do_setup_by_pip.bat: -------------------------------------------------------------------------------- 1 | pip.exe install PyQt5==5.15.1 2 | pip.exe install pyqt5-tools==5.15.1.3 3 | pip.exe install qt5-applications==5.15.1.2 4 | pip.exe install chardet==4.0.0 5 | 6 | pip.exe install PyInstaller==4.2 -------------------------------------------------------------------------------- /checker/env/pyinstaller_pack_f.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python -*- 2 | 3 | block_cipher = None 4 | 5 | 6 | a = Analysis(['..\\src\\main.py', 7 | '..\\src\\checkerWin.py'], 8 | binaries=[], 9 | datas=[], 10 | hiddenimports=[], 11 | hookspath=[], 12 | runtime_hooks=[], 13 | excludes=[], 14 | win_no_prefer_redirects=False, 15 | win_private_assemblies=False, 16 | cipher=block_cipher) 17 | pyz = PYZ(a.pure, a.zipped_data, 18 | cipher=block_cipher) 19 | exe = EXE(pyz, 20 | a.scripts, 21 | a.binaries, 22 | a.zipfiles, 23 | a.datas, 24 | name='MCUX-SDK-CodingStyleChecker', 25 | debug=False, 26 | strip=False, 27 | upx=True, 28 | runtime_tmpdir=None, 29 | console=False, 30 | icon='..\\img\\MCUX-SDK-CodingStyleChecker.ico') 31 | -------------------------------------------------------------------------------- /checker/gui/MCUX-SDK-CodingStyleChecker.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 728 10 | 581 11 | 12 | 13 | 14 | MCUXpresso SDK Coding Style Checker 15 | 16 | 17 | 18 | 19 | 20 | 10 21 | 10 22 | 81 23 | 71 24 | 25 | 26 | 27 | 28 | 微软雅黑 29 | 9 30 | 31 | 32 | 33 | Coding Style 34 | Setting 35 | 36 | 37 | 38 | 39 | 40 | 10 41 | 90 42 | 621 43 | 411 44 | 45 | 46 | 47 | Qt::ScrollBarAlwaysOn 48 | 49 | 50 | 51 | 52 | 53 | 10 54 | 510 55 | 711 56 | 23 57 | 58 | 59 | 60 | 24 61 | 62 | 63 | 64 | 65 | 66 | 190 67 | 60 68 | 441 69 | 21 70 | 71 | 72 | 73 | 74 | 75 | 76 | 100 77 | 50 78 | 91 79 | 31 80 | 81 | 82 | 83 | File/Folder Filter: 84 | 85 | 86 | 87 | 88 | 89 | 190 90 | 10 91 | 371 92 | 41 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 100 | 10 101 | 91 102 | 31 103 | 104 | 105 | 106 | Select File/Folder: 107 | 108 | 109 | 110 | 111 | 112 | 640 113 | 10 114 | 81 115 | 31 116 | 117 | 118 | 119 | Browse 120 | 121 | 122 | 123 | 124 | 125 | 570 126 | 10 127 | 61 128 | 31 129 | 130 | 131 | 132 | Is Folder 133 | 134 | 135 | 136 | 137 | 138 | 640 139 | 50 140 | 81 141 | 41 142 | 143 | 144 | 145 | 146 | 微软雅黑 147 | 75 148 | true 149 | 150 | 151 | 152 | Check 153 | 154 | 155 | 156 | 157 | 158 | 640 159 | 470 160 | 81 161 | 31 162 | 163 | 164 | 165 | Save Log 166 | 167 | 168 | 169 | 170 | 171 | 640 172 | 110 173 | 71 174 | 31 175 | 176 | 177 | 178 | Error Rate (%) 179 | 180 | 181 | 182 | 183 | 184 | 640 185 | 140 186 | 81 187 | 51 188 | 189 | 190 | 191 | 192 | 8 193 | 194 | 195 | 196 | 3 197 | 198 | 199 | 1 200 | 201 | 202 | 4 203 | 204 | 205 | QLCDNumber::Dec 206 | 207 | 208 | 100.000000000000000 209 | 210 | 211 | 100 212 | 213 | 214 | 215 | 216 | 217 | 640 218 | 200 219 | 81 220 | 31 221 | 222 | 223 | 224 | Total Error Lines 225 | 226 | 227 | 228 | 229 | 230 | 640 231 | 270 232 | 81 233 | 31 234 | 235 | 236 | 237 | Total Code Lines 238 | 239 | 240 | 241 | 242 | 243 | 640 244 | 300 245 | 81 246 | 31 247 | 248 | 249 | 250 | 251 | 252 | 253 | Qt::AlignCenter 254 | 255 | 256 | true 257 | 258 | 259 | 260 | 261 | 262 | 640 263 | 230 264 | 81 265 | 31 266 | 267 | 268 | 269 | Qt::AlignCenter 270 | 271 | 272 | true 273 | 274 | 275 | 276 | 277 | 278 | 279 | 0 280 | 0 281 | 728 282 | 21 283 | 284 | 285 | 286 | 287 | File 288 | 289 | 290 | 291 | 292 | Edit 293 | 294 | 295 | 296 | 297 | View 298 | 299 | 300 | 301 | 302 | Tools 303 | 304 | 305 | 306 | 307 | Window 308 | 309 | 310 | 311 | 312 | Help 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | Home Page 331 | 332 | 333 | true 334 | 335 | 336 | 337 | 338 | About Author 339 | 340 | 341 | 342 | 343 | Revision History 344 | 345 | 346 | 347 | 348 | 349 | 350 | -------------------------------------------------------------------------------- /checker/img/MCUX-SDK-CodingStyleChecker.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JayHeng/MCU-CodingStyleChecker/f49469a977562b79c6c818571ba6d1275bb70f82/checker/img/MCUX-SDK-CodingStyleChecker.PNG -------------------------------------------------------------------------------- /checker/img/MCUX-SDK-CodingStyleChecker.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JayHeng/MCU-CodingStyleChecker/f49469a977562b79c6c818571ba6d1275bb70f82/checker/img/MCUX-SDK-CodingStyleChecker.ico -------------------------------------------------------------------------------- /checker/log/_temp.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JayHeng/MCU-CodingStyleChecker/f49469a977562b79c6c818571ba6d1275bb70f82/checker/log/_temp.txt -------------------------------------------------------------------------------- /checker/src/checkerWin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file '.\MCUX-SDK-CodingStyleChecker.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.11.3 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_MainWindow(object): 12 | def setupUi(self, MainWindow): 13 | MainWindow.setObjectName("MainWindow") 14 | MainWindow.resize(728, 581) 15 | self.centralwidget = QtWidgets.QWidget(MainWindow) 16 | self.centralwidget.setObjectName("centralwidget") 17 | self.pushButton_codingStyleSetting = QtWidgets.QPushButton(self.centralwidget) 18 | self.pushButton_codingStyleSetting.setGeometry(QtCore.QRect(10, 10, 81, 71)) 19 | font = QtGui.QFont() 20 | font.setFamily("微软雅黑") 21 | font.setPointSize(9) 22 | self.pushButton_codingStyleSetting.setFont(font) 23 | self.pushButton_codingStyleSetting.setObjectName("pushButton_codingStyleSetting") 24 | self.textEdit_log = QtWidgets.QTextEdit(self.centralwidget) 25 | self.textEdit_log.setGeometry(QtCore.QRect(10, 90, 621, 411)) 26 | self.textEdit_log.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) 27 | self.textEdit_log.setObjectName("textEdit_log") 28 | self.progressBar = QtWidgets.QProgressBar(self.centralwidget) 29 | self.progressBar.setGeometry(QtCore.QRect(10, 510, 711, 23)) 30 | self.progressBar.setProperty("value", 24) 31 | self.progressBar.setObjectName("progressBar") 32 | self.textEdit_fileFolderFilter = QtWidgets.QTextEdit(self.centralwidget) 33 | self.textEdit_fileFolderFilter.setGeometry(QtCore.QRect(190, 60, 441, 21)) 34 | self.textEdit_fileFolderFilter.setObjectName("textEdit_fileFolderFilter") 35 | self.label_fileFolderFilter = QtWidgets.QLabel(self.centralwidget) 36 | self.label_fileFolderFilter.setGeometry(QtCore.QRect(100, 50, 91, 31)) 37 | self.label_fileFolderFilter.setObjectName("label_fileFolderFilter") 38 | self.textEdit_inputFileFolder = QtWidgets.QTextEdit(self.centralwidget) 39 | self.textEdit_inputFileFolder.setGeometry(QtCore.QRect(190, 10, 371, 41)) 40 | self.textEdit_inputFileFolder.setObjectName("textEdit_inputFileFolder") 41 | self.label_selectFileFolder = QtWidgets.QLabel(self.centralwidget) 42 | self.label_selectFileFolder.setGeometry(QtCore.QRect(100, 10, 91, 31)) 43 | self.label_selectFileFolder.setObjectName("label_selectFileFolder") 44 | self.pushButton_browseFileFolder = QtWidgets.QPushButton(self.centralwidget) 45 | self.pushButton_browseFileFolder.setGeometry(QtCore.QRect(640, 10, 81, 31)) 46 | self.pushButton_browseFileFolder.setObjectName("pushButton_browseFileFolder") 47 | self.checkBox_isFolder = QtWidgets.QCheckBox(self.centralwidget) 48 | self.checkBox_isFolder.setGeometry(QtCore.QRect(570, 10, 61, 31)) 49 | self.checkBox_isFolder.setObjectName("checkBox_isFolder") 50 | self.pushButton_doCheck = QtWidgets.QPushButton(self.centralwidget) 51 | self.pushButton_doCheck.setGeometry(QtCore.QRect(640, 50, 81, 41)) 52 | font = QtGui.QFont() 53 | font.setFamily("微软雅黑") 54 | font.setBold(True) 55 | font.setWeight(75) 56 | self.pushButton_doCheck.setFont(font) 57 | self.pushButton_doCheck.setObjectName("pushButton_doCheck") 58 | self.pushButton_saveLog = QtWidgets.QPushButton(self.centralwidget) 59 | self.pushButton_saveLog.setGeometry(QtCore.QRect(640, 470, 81, 31)) 60 | self.pushButton_saveLog.setObjectName("pushButton_saveLog") 61 | self.label_errorRate = QtWidgets.QLabel(self.centralwidget) 62 | self.label_errorRate.setGeometry(QtCore.QRect(640, 110, 71, 31)) 63 | self.label_errorRate.setObjectName("label_errorRate") 64 | self.lcdNumber_errorRate = QtWidgets.QLCDNumber(self.centralwidget) 65 | self.lcdNumber_errorRate.setGeometry(QtCore.QRect(640, 140, 81, 51)) 66 | font = QtGui.QFont() 67 | font.setPointSize(8) 68 | self.lcdNumber_errorRate.setFont(font) 69 | self.lcdNumber_errorRate.setLineWidth(3) 70 | self.lcdNumber_errorRate.setMidLineWidth(1) 71 | self.lcdNumber_errorRate.setDigitCount(4) 72 | self.lcdNumber_errorRate.setMode(QtWidgets.QLCDNumber.Dec) 73 | self.lcdNumber_errorRate.setProperty("value", 100.0) 74 | self.lcdNumber_errorRate.setProperty("intValue", 100) 75 | self.lcdNumber_errorRate.setObjectName("lcdNumber_errorRate") 76 | self.label_totalErrorLines = QtWidgets.QLabel(self.centralwidget) 77 | self.label_totalErrorLines.setGeometry(QtCore.QRect(640, 200, 81, 31)) 78 | self.label_totalErrorLines.setObjectName("label_totalErrorLines") 79 | self.label_totalCodeLines = QtWidgets.QLabel(self.centralwidget) 80 | self.label_totalCodeLines.setGeometry(QtCore.QRect(640, 270, 81, 31)) 81 | self.label_totalCodeLines.setObjectName("label_totalCodeLines") 82 | self.lineEdit_totalCodeLines = QtWidgets.QLineEdit(self.centralwidget) 83 | self.lineEdit_totalCodeLines.setGeometry(QtCore.QRect(640, 300, 81, 31)) 84 | self.lineEdit_totalCodeLines.setText("") 85 | self.lineEdit_totalCodeLines.setAlignment(QtCore.Qt.AlignCenter) 86 | self.lineEdit_totalCodeLines.setReadOnly(True) 87 | self.lineEdit_totalCodeLines.setObjectName("lineEdit_totalCodeLines") 88 | self.lineEdit_totalErrorLines = QtWidgets.QLineEdit(self.centralwidget) 89 | self.lineEdit_totalErrorLines.setGeometry(QtCore.QRect(640, 230, 81, 31)) 90 | self.lineEdit_totalErrorLines.setAlignment(QtCore.Qt.AlignCenter) 91 | self.lineEdit_totalErrorLines.setReadOnly(True) 92 | self.lineEdit_totalErrorLines.setObjectName("lineEdit_totalErrorLines") 93 | MainWindow.setCentralWidget(self.centralwidget) 94 | self.menubar = QtWidgets.QMenuBar(MainWindow) 95 | self.menubar.setGeometry(QtCore.QRect(0, 0, 728, 21)) 96 | self.menubar.setObjectName("menubar") 97 | self.menuFile = QtWidgets.QMenu(self.menubar) 98 | self.menuFile.setObjectName("menuFile") 99 | self.menuEdit = QtWidgets.QMenu(self.menubar) 100 | self.menuEdit.setObjectName("menuEdit") 101 | self.menuView = QtWidgets.QMenu(self.menubar) 102 | self.menuView.setObjectName("menuView") 103 | self.menuTools = QtWidgets.QMenu(self.menubar) 104 | self.menuTools.setObjectName("menuTools") 105 | self.menuWindow = QtWidgets.QMenu(self.menubar) 106 | self.menuWindow.setObjectName("menuWindow") 107 | self.menuHelp = QtWidgets.QMenu(self.menubar) 108 | self.menuHelp.setObjectName("menuHelp") 109 | MainWindow.setMenuBar(self.menubar) 110 | self.statusbar = QtWidgets.QStatusBar(MainWindow) 111 | self.statusbar.setObjectName("statusbar") 112 | MainWindow.setStatusBar(self.statusbar) 113 | self.actionMenuHelpHomePage = QtWidgets.QAction(MainWindow) 114 | self.actionMenuHelpHomePage.setAutoRepeat(True) 115 | self.actionMenuHelpHomePage.setObjectName("actionMenuHelpHomePage") 116 | self.actionMenuHelpAboutAuthor = QtWidgets.QAction(MainWindow) 117 | self.actionMenuHelpAboutAuthor.setObjectName("actionMenuHelpAboutAuthor") 118 | self.actionMenuHelpRevisionHistory = QtWidgets.QAction(MainWindow) 119 | self.actionMenuHelpRevisionHistory.setObjectName("actionMenuHelpRevisionHistory") 120 | self.menuHelp.addSeparator() 121 | self.menuHelp.addAction(self.actionMenuHelpHomePage) 122 | self.menuHelp.addAction(self.actionMenuHelpAboutAuthor) 123 | self.menuHelp.addAction(self.actionMenuHelpRevisionHistory) 124 | self.menuHelp.addSeparator() 125 | self.menubar.addAction(self.menuFile.menuAction()) 126 | self.menubar.addAction(self.menuEdit.menuAction()) 127 | self.menubar.addAction(self.menuView.menuAction()) 128 | self.menubar.addAction(self.menuTools.menuAction()) 129 | self.menubar.addAction(self.menuWindow.menuAction()) 130 | self.menubar.addAction(self.menuHelp.menuAction()) 131 | 132 | self.retranslateUi(MainWindow) 133 | QtCore.QMetaObject.connectSlotsByName(MainWindow) 134 | 135 | def retranslateUi(self, MainWindow): 136 | _translate = QtCore.QCoreApplication.translate 137 | MainWindow.setWindowTitle(_translate("MainWindow", "MCUXpresso SDK Coding Style Checker")) 138 | self.pushButton_codingStyleSetting.setText(_translate("MainWindow", "Coding Style \n" 139 | " Setting")) 140 | self.label_fileFolderFilter.setText(_translate("MainWindow", "File/Folder Filter:")) 141 | self.label_selectFileFolder.setText(_translate("MainWindow", "Select File/Folder:")) 142 | self.pushButton_browseFileFolder.setText(_translate("MainWindow", "Browse")) 143 | self.checkBox_isFolder.setText(_translate("MainWindow", "Is Folder")) 144 | self.pushButton_doCheck.setText(_translate("MainWindow", "Check")) 145 | self.pushButton_saveLog.setText(_translate("MainWindow", "Save Log")) 146 | self.label_errorRate.setText(_translate("MainWindow", "Error Rate (%)")) 147 | self.label_totalErrorLines.setText(_translate("MainWindow", "Total Error Lines")) 148 | self.label_totalCodeLines.setText(_translate("MainWindow", "Total Code Lines")) 149 | self.menuFile.setTitle(_translate("MainWindow", "File")) 150 | self.menuEdit.setTitle(_translate("MainWindow", "Edit")) 151 | self.menuView.setTitle(_translate("MainWindow", "View")) 152 | self.menuTools.setTitle(_translate("MainWindow", "Tools")) 153 | self.menuWindow.setTitle(_translate("MainWindow", "Window")) 154 | self.menuHelp.setTitle(_translate("MainWindow", "Help")) 155 | self.actionMenuHelpHomePage.setText(_translate("MainWindow", "Home Page")) 156 | self.actionMenuHelpAboutAuthor.setText(_translate("MainWindow", "About Author")) 157 | self.actionMenuHelpRevisionHistory.setText(_translate("MainWindow", "Revision History")) 158 | 159 | -------------------------------------------------------------------------------- /checker/src/main.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: UTF-8 -*- 3 | import sys 4 | import os 5 | import time 6 | import chardet 7 | import uilang 8 | from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox 9 | from PyQt5.QtGui import QIcon 10 | from checkerWin import * 11 | 12 | kFileType_Source = u".c" 13 | kFileType_Header = u".h" 14 | 15 | kSegmentType_Definition = 0 16 | kSegmentType_Variable = 1 17 | kSegmentType_Prototype = 2 18 | kSegmentType_Code = 3 19 | kSegmentType_API = 4 20 | 21 | kLangKeyWord_Static = u"static" 22 | 23 | kLangKeyWordList_Control = [u"if", u"else if", u"for", u"while", u"switch"] 24 | 25 | class checkerMain(QMainWindow, Ui_MainWindow): 26 | 27 | def __init__(self, parent=None): 28 | super(checkerMain, self).__init__(parent) 29 | self.setupUi(self) 30 | self._register_callbacks() 31 | self._init_segment_magic() 32 | self.progressBar.reset() 33 | self.lcdNumber_errorRate.display(0) 34 | self.fileFolderName = None 35 | self.continuationContent = '' 36 | self.bracePairs = 0 37 | self.onProgressEnumName = u"" 38 | self.isEnumOnProgress = False 39 | self.onProgressStructName = u"" 40 | self.isStructOnProgress = False 41 | self.totalErrorLines = 0 42 | self.totalCodeLines = 0 43 | 44 | def _init_segment_magic(self): 45 | self.segmentMagicStart = u"/*******************************************************************************" 46 | self.definitionMagic = u" * Definitions" 47 | self.variableMagic = u" * Variables" 48 | self.prototypeMagic = u" * Prototypes" 49 | self.codeMagic = u" * Code" 50 | self.apiMagic = u" * API" 51 | self.segmentMagicEnd = u" ******************************************************************************/" 52 | 53 | def _register_callbacks(self): 54 | self.pushButton_browseFileFolder.clicked.connect(self.callbackBrowseFileFolder) 55 | self.pushButton_doCheck.clicked.connect(self.callbackDoCheck) 56 | self.pushButton_saveLog.clicked.connect(self.callbackSaveLog) 57 | self.actionMenuHelpHomePage.triggered.connect(self.callbackShowHomePage) 58 | self.actionMenuHelpAboutAuthor.triggered.connect(self.callbackShowAboutAuthor) 59 | self.actionMenuHelpRevisionHistory.triggered.connect(self.callbackShowRevisionHistory) 60 | 61 | def callbackBrowseFileFolder(self): 62 | if self.checkBox_isFolder.isChecked(): 63 | self.fileFolderName = QtWidgets.QFileDialog.getExistingDirectory(self, u"Browse Folder", os.getcwd()) 64 | else: 65 | self.fileFolderName, fileType = QtWidgets.QFileDialog.getOpenFileName(self, u"Browse File", os.getcwd(), "All Files(*);;Source Files(*.c)") 66 | #self.fileFolderName = self.fileFolderName.encode('utf-8').encode("gbk") 67 | self.textEdit_inputFileFolder.setPlainText(self.fileFolderName) 68 | 69 | def _file_check_separator(self, filename): 70 | self.textEdit_log.append(u">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>----------File----------<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<") 71 | self.textEdit_log.append(u"Start to check " + filename + "\n") 72 | 73 | def _is_utf8_ascii_file(self, filename): 74 | self._file_check_separator(filename) 75 | fileObj = open(filename,'rb') 76 | fileDat = fileObj.read() 77 | # https://chardet.readthedocs.io/en/latest/supported-encodings.html 78 | fileProperties = chardet.detect(fileDat) 79 | fileObj.close() 80 | if fileProperties.get('confidence') == 1.0 and \ 81 | (fileProperties.get('encoding') != 'utf-8' or \ 82 | fileProperties.get('encoding') != 'ascii'): 83 | return True 84 | else: 85 | self.textEdit_log.append(u"【ERROR】: Cannot support Non-'UTF-8'/'ASCII'(100%) encoded file \n") 86 | return False 87 | 88 | def _check_segment(self, content, segmentMagic): 89 | segment = self.segmentMagicStart + u"\n" + segmentMagic + u"\n" + self.segmentMagicEnd 90 | if content.find(segment) == -1: 91 | self.textEdit_log.append(u"【ERROR】: Below general comment is missed in the file") 92 | self.textEdit_log.append(segment) 93 | 94 | def _check_segments(self, filename, fileType): 95 | with open(filename, mode="r", encoding="utf-8") as fileObj: 96 | content = fileObj.read() 97 | self._check_segment(content, self.definitionMagic) 98 | if fileType == kFileType_Header: 99 | self._check_segment(content, self.apiMagic) 100 | elif fileType == kFileType_Source: 101 | self._check_segment(content, self.variableMagic) 102 | self._check_segment(content, self.prototypeMagic) 103 | self._check_segment(content, self.codeMagic) 104 | else: 105 | pass 106 | fileObj.close() 107 | 108 | def _update_total_error_lines(self): 109 | self.lineEdit_totalErrorLines.clear() 110 | self.lineEdit_totalErrorLines.setText(str(self.totalErrorLines)) 111 | 112 | def _update_total_code_lines(self): 113 | self.lineEdit_totalCodeLines.clear() 114 | self.lineEdit_totalCodeLines.setText(str(self.totalCodeLines)) 115 | 116 | def _print_common_error(self, line, error): 117 | if line != None: 118 | self.textEdit_log.append(u"【ERROR】 Line " + str(line) + u": " + error) 119 | else: 120 | self.textEdit_log.append(u"【ERROR】: " + error) 121 | self.totalErrorLines += 1 122 | self._update_total_error_lines() 123 | 124 | def _common_find_continuation_character(self, content): 125 | contIndex = content.rfind(u"\\\n") 126 | if (contIndex != -1) and (contIndex == len(content) - len(u"\\\n")): 127 | self.continuationContent += content[0:contIndex] 128 | return True 129 | else: 130 | if self.continuationContent != '': 131 | self.continuationContent += content 132 | return False 133 | 134 | def _common_remove_initial_blanks(self, content): 135 | startIndex = 0 136 | while True: 137 | if startIndex == len(content): 138 | return None 139 | elif content[startIndex] != u" ": 140 | break 141 | else: 142 | startIndex += 1 143 | return content[startIndex:len(content)] 144 | 145 | def _common_line_preprocess(self, content): 146 | if self._common_find_continuation_character(content): 147 | return None, False 148 | else: 149 | if self.continuationContent != '': 150 | content = self.continuationContent 151 | self.continuationContent = '' 152 | content = self._common_remove_initial_blanks(content) 153 | if content == None: 154 | return content, False 155 | else: 156 | return content, True 157 | 158 | def _common_find_invalid_code_line(self, content): 159 | return ((content.find(u"/*") == 0) or \ 160 | (content.find(u"#if") == 0) or \ 161 | (content.find(u"#else") == 0) or \ 162 | (content.find(u"#endif") == 0)) 163 | 164 | def _is_camel_case_naming_style(self, content): 165 | return ((content[0].isalpha() and content[0].islower()) and \ 166 | (content.find(u"_") == -1)) 167 | 168 | def _is_linux_underline_naming_style(self, content): 169 | return content.islower() and content[0] != u"_" 170 | 171 | def _is_pascal_naming_style(self, content): 172 | idx = content.find(u"_") 173 | if idx != -1: 174 | if (idx == 0) or (not (content[0:idx].isalpha() and content[0:idx].isupper())): 175 | return False 176 | idx += 1 177 | else: 178 | idx = 0 179 | return ((content[idx].isalpha() and content[idx].isupper()) and \ 180 | (content[idx:len(content)].find(u"_") == -1)) 181 | 182 | def _get_definition_word(self, content, startIdx, endChar): 183 | wordLoc = [0, 0] 184 | while True: 185 | startIdx += 1 186 | if content[startIdx] == u" " or content[startIdx] == endChar or content[startIdx] == u"\n": 187 | if wordLoc[0] != 0: 188 | wordLoc[1] = startIdx 189 | break 190 | elif wordLoc[0] == 0: 191 | wordLoc[0] = startIdx 192 | else: 193 | pass 194 | return content[wordLoc[0]:wordLoc[1]] 195 | 196 | def _is_valid_macro_name(self, macro): 197 | return macro.isupper() and macro[0] != u"_" 198 | 199 | def _do_check_macro(self, line, content): 200 | idx = len(u"#define") - 1 201 | macro = self._get_definition_word(content, idx, u"(") 202 | if not self._is_valid_macro_name(macro): 203 | self._print_common_error(line, u"This macro <" + macro + u"> starts with '_' or it is not all capitalized") 204 | 205 | def _is_valid_enum_struct_type_name(self, mtype): 206 | return mtype.islower() and mtype[0] == u"_" 207 | 208 | def _is_valid_enum_struct_typedef_name(self, mtype): 209 | return mtype.islower() and mtype[0] != u"_" and mtype[len(mtype)-2:len(mtype)] == u"_t" 210 | 211 | def _is_valid_enumerator_name(self, enum): 212 | return enum[0] == u"k" and enum[1].isupper() 213 | 214 | def _do_check_enum(self, line, content): 215 | if not self.isEnumOnProgress: 216 | idx = content.find(u"enum") + len(u"enum") - 1 217 | enumType = self._get_definition_word(content, idx, u"{") 218 | if not self._is_valid_enum_struct_type_name(enumType): 219 | self._print_common_error(line, u"This enum type name <" + enumType + u"> is not valid") 220 | else: 221 | self.onProgressEnumName = enumType 222 | self.isEnumOnProgress = True 223 | else: 224 | if content[0] == "}": 225 | enumTypedef = self._get_definition_word(content, 0, u";") 226 | if enumTypedef[0] != u";" and (not self._is_valid_enum_struct_typedef_name(enumTypedef)): 227 | self._print_common_error(line, u"This enum typedef name <" + enumTypedef + u"> is not valid") 228 | self.isEnumOnProgress = False 229 | elif content[0] != "{": 230 | # If first invalid enumerator is found, then it will stop checking the following enumerators (nno matter it is valid or not) 231 | if not self._is_valid_enumerator_name(content[0:2]): 232 | self._print_common_error(line, u"This enum type <" + self.onProgressEnumName + u"> contains invalid enumerator name") 233 | self.isEnumOnProgress = False 234 | 235 | def _is_valid_struct_member_name(self, struct): 236 | return self._is_valid_variable_name(struct, False) 237 | 238 | def _find_valid_local_variable(self, content, isBssSection=True): 239 | # Try to find code expression according to the first "=" or ";" 240 | midIndex = -1 241 | if not isBssSection: 242 | midIndex = content.find(u"=") 243 | endIndex = content.find(u";") 244 | variable = None 245 | fndIndex = 0 246 | if midIndex != -1: 247 | # In case there are more than one blanks before "=" 248 | while True: 249 | midIndex -= 1 250 | if content[midIndex] != u" ": 251 | break 252 | fndIndex = midIndex + 1 253 | elif endIndex != -1: 254 | fndIndex = endIndex 255 | else: 256 | return True 257 | expression = content[0:fndIndex] 258 | # Try to find variable word according to the last blank in code expression 259 | blankIndex = expression.rfind(u" ") 260 | variable = expression[blankIndex+1:fndIndex] 261 | while True: 262 | if variable[0] == u"*": 263 | variable = variable[1:len(variable)] 264 | else: 265 | break 266 | return self._is_valid_variable_name(variable, False) 267 | 268 | def _do_check_struct(self, line, content): 269 | if not self.isStructOnProgress: 270 | idx = content.find(u"struct") + len(u"struct") - 1 271 | structType = self._get_definition_word(content, idx, u"{") 272 | if not self._is_valid_enum_struct_type_name(structType): 273 | self._print_common_error(line, u"This struct type name <" + structType + u"> is not valid") 274 | else: 275 | self.onProgressStructName = structType 276 | self.isStructOnProgress = True 277 | else: 278 | if content[0] == "}": 279 | structTypedef = self._get_definition_word(content, 0, u";") 280 | if structTypedef[0] != u";" and (not self._is_valid_enum_struct_typedef_name(structTypedef)): 281 | self._print_common_error(line, u"This struct typedef name <" + structTypedef + u"> is not valid") 282 | self.isStructOnProgress = False 283 | elif content[0] != "{": 284 | # If first invalid member is found, then it will stop checking the following member (nno matter it is valid or not) 285 | if not self._find_valid_local_variable(content): 286 | self._print_common_error(line, u"This struct type <" + self.onProgressStructName + u"> contains invalid member name") 287 | self.isStructOnProgress = False 288 | 289 | def _do_check_definition(self, line, content): 290 | content, status = self._common_line_preprocess(content) 291 | if not status: 292 | return 293 | if not (self._common_find_invalid_code_line(content)): 294 | if content.find(u"#define") == 0: 295 | self._do_check_macro(line, content) 296 | else: 297 | if self.isEnumOnProgress or \ 298 | (content.find(u"enum") == 0 or (content.find(u"typedef") == 0 and content.find(u"enum") != -1)): 299 | self._do_check_enum(line, content) 300 | elif self.isStructOnProgress or \ 301 | (content.find(u"struct") == 0 or (content.find(u"typedef") == 0 and content.find(u"struct") != -1)): 302 | self._do_check_struct(line, content) 303 | else: 304 | pass 305 | 306 | def _is_valid_variable_name(self, variable, isGlobal): 307 | idx = 0 308 | if isGlobal: 309 | idx = 2 310 | return self._is_camel_case_naming_style(variable[idx:len(variable)]) 311 | 312 | def _do_check_global_variable(self, line, content): 313 | content, status = self._common_line_preprocess(content) 314 | if not status: 315 | return 316 | if not (self._common_find_invalid_code_line(content) or \ 317 | (content.find(u".") == 0) or \ 318 | (content.find(u"{") == 0) or \ 319 | (content.find(u"}") == 0)): 320 | # Try to find code expression according to the first "=" or ";" 321 | midIndex = content.find(u"=") 322 | endIndex = content.find(u";") 323 | variable = None 324 | fndIndex = 0 325 | if midIndex != -1: 326 | # In case there are more than one blanks before "=" 327 | while True: 328 | midIndex -= 1 329 | if content[midIndex] != u" ": 330 | break 331 | fndIndex = midIndex + 1 332 | elif endIndex != -1: 333 | fndIndex = endIndex 334 | else: 335 | return 336 | # If there is a "," in the code expression, that means each line has more than one variable 337 | expression = content[0:fndIndex] 338 | if expression.find(u",") != -1: 339 | self._print_common_error(line, u"Only one variable can be defined per line") 340 | return 341 | else: 342 | # Try to find variable word according to the last blank in code expression 343 | blankIndex = expression.rfind(u" ") 344 | variable = expression[blankIndex+1:fndIndex] 345 | #self.textEdit_log.insertPlainText("-- Find " + variable + "\n") 346 | # Special operation for pointer variable 347 | while True: 348 | if variable[0] == u"*": 349 | variable = variable[1:len(variable)] 350 | else: 351 | break 352 | # Process prefix in variable word 353 | if kLangKeyWord_Static in expression: 354 | if variable[0:2] != u"s_": 355 | self._print_common_error(line, u"A prefix 's_' is missed in the static variable <" + variable + u">") 356 | return 357 | else: 358 | if variable[0:2] != u"g_": 359 | self._print_common_error(line, u"A prefix 'g_' is missed in the global variable <" + variable + u">") 360 | return 361 | if not self._is_valid_variable_name(variable, True): 362 | self._print_common_error(line, u"This global variable <" + variable + u"> is not named after CamelCase") 363 | return 364 | 365 | def _is_valid_function_name(self, function): 366 | return self._is_pascal_naming_style(function) or self._is_linux_underline_naming_style(function) 367 | 368 | def _do_check_code(self, line, content): 369 | content, status = self._common_line_preprocess(content) 370 | if not status: 371 | return 372 | if not self._common_find_invalid_code_line(content): 373 | if not self.bracePairs: 374 | # Try to find function expression according to the first "(" 375 | fndIndex = content.find(u"(") 376 | if fndIndex != -1: 377 | expression = content[0:fndIndex] 378 | # Try to find function name according to the last blank in function expression 379 | blankIndex = expression.rfind(u" ") 380 | function = expression[blankIndex+1:fndIndex] 381 | #self.textEdit_log.insertPlainText("-- Find " + function + "\n") 382 | if not self._is_valid_function_name(function): 383 | self._print_common_error(line, u"This function <" + function + u"()> starts with '_' or it is not named after Pascal / Linux style") 384 | # Count the "{ }" pair, function name resides out of any pair 385 | if content.find(u"{") != -1: 386 | self.bracePairs += 1 387 | elif content.find(u"}") != -1: 388 | if self.bracePairs: 389 | self.bracePairs -= 1 390 | else: 391 | pass 392 | 393 | def _do_check_source_file(self, sourceFilename): 394 | self._check_segments(sourceFilename, kFileType_Source) 395 | with open(sourceFilename, mode="r", encoding="utf-8") as fileObj: 396 | lineCount = 0 397 | blankLines = 0 398 | isSegmentFound = False 399 | segmentType = None 400 | for lineContent in fileObj.readlines(): 401 | lineCount += 1 402 | #self.textEdit_log.insertPlainText("Line " + str(lineCount) + lineContent) 403 | if lineContent == u"\n": 404 | blankLines += 1 405 | elif isSegmentFound: 406 | isSegmentFound = False 407 | if lineContent.find(self.definitionMagic) != -1: 408 | segmentType = kSegmentType_Definition 409 | elif lineContent.find(self.variableMagic) != -1: 410 | segmentType = kSegmentType_Variable 411 | elif lineContent.find(self.prototypeMagic) != -1: 412 | segmentType = kSegmentType_Prototype 413 | elif lineContent.find(self.codeMagic) != -1: 414 | segmentType = kSegmentType_Code 415 | else: 416 | pass 417 | elif lineContent.find(self.segmentMagicStart) != -1: 418 | isSegmentFound = True 419 | else: 420 | if segmentType == kSegmentType_Definition: 421 | #self.textEdit_log.insertPlainText("_do_check_definition(): \n") 422 | try: 423 | self._do_check_definition(lineCount, lineContent) 424 | except: 425 | pass 426 | elif segmentType == kSegmentType_Variable: 427 | #self.textEdit_log.insertPlainText("_do_check_global_variable(): \n") 428 | try: 429 | self._do_check_global_variable(lineCount, lineContent) 430 | except: 431 | pass 432 | elif segmentType == kSegmentType_Prototype: 433 | pass 434 | elif segmentType == kSegmentType_Code: 435 | #self.textEdit_log.insertPlainText("_do_check_code(): \n") 436 | try: 437 | self._do_check_code(lineCount, lineContent) 438 | except: 439 | pass 440 | else: 441 | pass 442 | fileObj.close() 443 | self.textEdit_log.append(u"") 444 | self.totalCodeLines += lineCount - blankLines 445 | self._update_total_code_lines() 446 | 447 | def _check_header_guard_macro(self, filename): 448 | with open(filename, mode="r", encoding="utf-8") as fileObj: 449 | name = os.path.split(filename)[1] 450 | name = name.upper() 451 | name = name.replace(u".", u"_") 452 | name = u"_" + name + u"_" 453 | magic = u"#ifndef " + name 454 | content = fileObj.read() 455 | if content.find(magic) == -1: 456 | self._print_common_error(None, u"<" + magic + u"> is missed in this header file") 457 | fileObj.close() 458 | 459 | def _do_check_header_file(self, headerFilename): 460 | self._check_header_guard_macro(headerFilename) 461 | self._check_segments(headerFilename, kFileType_Header) 462 | with open(headerFilename, mode="r", encoding="utf-8") as fileObj: 463 | lineCount = 0 464 | blankLines = 0 465 | isSegmentFound = False 466 | segmentType = None 467 | for lineContent in fileObj.readlines(): 468 | lineCount += 1 469 | #self.textEdit_log.insertPlainText("Line " + str(lineCount) + lineContent) 470 | if lineContent == u"\n": 471 | blankLines += 1 472 | elif isSegmentFound: 473 | isSegmentFound = False 474 | if lineContent.find(self.definitionMagic) != -1: 475 | segmentType = kSegmentType_Definition 476 | elif lineContent.find(self.apiMagic) != -1: 477 | segmentType = kSegmentType_API 478 | else: 479 | pass 480 | elif lineContent.find(self.segmentMagicStart) != -1: 481 | isSegmentFound = True 482 | else: 483 | if segmentType == kSegmentType_Definition: 484 | #self.textEdit_log.insertPlainText("_do_check_definition(): \n") 485 | try: 486 | self._do_check_definition(lineCount, lineContent) 487 | except: 488 | pass 489 | elif segmentType == kSegmentType_API: 490 | pass 491 | else: 492 | pass 493 | fileObj.close() 494 | self.textEdit_log.append(u"") 495 | self.totalCodeLines += lineCount - blankLines 496 | self._update_total_code_lines() 497 | 498 | def _detect_file_type(self, filename): 499 | if os.path.isfile(filename): 500 | filetype = os.path.splitext(filename)[1] 501 | if filetype == kFileType_Header: 502 | if not self._is_utf8_ascii_file(filename): 503 | return 504 | self._do_check_header_file(filename) 505 | elif filetype == kFileType_Source: 506 | if not self._is_utf8_ascii_file(filename): 507 | return 508 | self._do_check_source_file(filename) 509 | else: 510 | pass 511 | 512 | def _showErrorRate(self): 513 | rate = self.totalErrorLines * 100.0 / self.totalCodeLines 514 | self.lcdNumber_errorRate.display(rate) 515 | 516 | def callbackDoCheck(self): 517 | self.textEdit_log.clear() 518 | if self.fileFolderName != None: 519 | self.totalErrorLines = 0 520 | self.totalCodeLines = 0 521 | self._update_total_error_lines() 522 | self._update_total_code_lines() 523 | if os.path.isdir(self.fileFolderName): 524 | for root, dirs, files in os.walk(self.fileFolderName, topdown=True): 525 | for name in files: 526 | self._detect_file_type(os.path.join(root, name)) 527 | else: 528 | self._detect_file_type(self.fileFolderName) 529 | self._showErrorRate() 530 | 531 | def callbackSaveLog(self): 532 | logPath = os.path.abspath(os.path.dirname(__file__)) 533 | logPath = os.path.join(os.path.dirname(logPath), u"log") 534 | logFilename = os.path.join(logPath, time.strftime('%Y-%m-%d_%Hh%Mm%Ss',time.localtime(time.time())) + '.txt') 535 | with open(logFilename, mode="w", encoding="utf-8") as fileObj: 536 | fileObj.write(self.textEdit_log.toPlainText()) 537 | fileObj.close() 538 | QMessageBox.about(self, u"Info", u"Log is saved in file: " + logFilename + u"\n") 539 | 540 | def callbackShowHomePage(self): 541 | QMessageBox.about(self, uilang.kMsgLanguageContentDict['homePage_title'][0], uilang.kMsgLanguageContentDict['homePage_info'][0] ) 542 | 543 | def callbackShowAboutAuthor(self): 544 | QMessageBox.about(self, uilang.kMsgLanguageContentDict['aboutAuthor_title'][0], uilang.kMsgLanguageContentDict['aboutAuthor_author'][0] ) 545 | 546 | def callbackShowRevisionHistory(self): 547 | QMessageBox.about(self, uilang.kMsgLanguageContentDict['revisionHistory_title'][0], uilang.kMsgLanguageContentDict['revisionHistory_v1_0'][0] ) 548 | 549 | if __name__ == '__main__': 550 | app = QApplication(sys.argv) 551 | main_win = checkerMain() 552 | main_win.setWindowTitle(u"MCUXpresso SDK Coding Style Checker v0.5") 553 | main_win.setWindowIcon(QIcon(u"../img/MCUX-SDK-CodingStyleChecker.ico")) 554 | main_win.show() 555 | sys.exit(app.exec_()) -------------------------------------------------------------------------------- /checker/src/uilang.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import sys 4 | import os 5 | 6 | kRevision_1_0_en = "【v0.5】 \n" + \ 7 | " Feature: \n" + \ 8 | " 1. Can select file or folder to check \n" + \ 9 | " 2. Auto detect .c/.h file, and the file should be utf-8/ascii encoded \n" + \ 10 | " 3. Can show statistical info of check results \n" + \ 11 | " 4. Can save check result log \n" + \ 12 | " 5. Can check general comment (Definitions/Variables/Prototypes/Code/API) \n" + \ 13 | " 6. Can check global variable name \n" + \ 14 | " 7. Can check function name \n" + \ 15 | " 8. Can check macro name \n" + \ 16 | " 9. Can check enumeration type name \n" + \ 17 | " 10. Can check struct type name \n" + \ 18 | " 11. Can check header file guard macro \n\n" 19 | 20 | kMsgLanguageContentDict = { 21 | 'homePage_title': ['Home Page'], 22 | 'homePage_info': ['https://github.com/JayHeng/MCUX-SDK-Coding-Style.git \n'], 23 | 'aboutAuthor_title': ['About Author'], 24 | 'aboutAuthor_author': [u"Author: 痞子衡 \n" + \ 25 | u"Email: jie.heng@nxp.com \n" + \ 26 | u"Email: hengjie1989@foxmail.com \n" + \ 27 | u"Blog: 痞子衡嵌入式 https://www.cnblogs.com/henjay724/ \n"], 28 | 'revisionHistory_title': ['Revision History'], 29 | 'revisionHistory_v1_0': [kRevision_1_0_en], 30 | 31 | } -------------------------------------------------------------------------------- /checker/test/test_gbk.c: -------------------------------------------------------------------------------- 1 | /* 包含头文件代码 */ 2 | #include "template.h" 3 | /******************************************************************************* 4 | * Definitions 5 | ******************************************************************************/ 6 | 7 | /* 私有(仅本源文件内使用)宏、枚举、结构体的定义 */ 8 | 9 | /* 宏命名使用下划线命名法,单词全大写 */ 10 | #define MAX_DEVICES (128U) /* 无符号整型数字,均应加 "U" 后缀 */ 11 | 12 | /******************************************************************************* 13 | * Variables 14 | ******************************************************************************/ 15 | 16 | /* 所有全局变量(外部,静态,常量,指针)的定义 */ 17 | 18 | /* 变量命名使用 CamelCase (小骆驼峰法),即第一个单词以小写字母开始, 19 | 第二个单词以及后面的每一个单词的首字母大写 */ 20 | uint32_t g_deviceIndex = 0; /* 作用域可在文件外的全局变量加 g_ 前缀 */ 21 | static device_config_t s_deviceConfig; /* 使用 static 修饰的全局变量加 s_ 前缀 */ 22 | const uint32_t g_maxDevices = MAX_DEVICES; 23 | static volatile uint8_t *s_deviceData; /* volatile, const 修饰或指针型变量, 24 | 无需任何特殊表示 */ 25 | 26 | /******************************************************************************* 27 | * Prototypes 28 | ******************************************************************************/ 29 | 30 | /* 内部函数(即 static 修饰)的声明 */ 31 | 32 | static uint32_t GetDeviceIndex(void); 33 | 34 | /******************************************************************************* 35 | * Code 36 | ******************************************************************************/ 37 | 38 | /* 所有函数(外部,内部)的定义 */ 39 | 40 | /* 函数命名使用 Pascal (大骆驼峰法),即把变量名称的第一个字母也大写 41 | 函数命名可由 [Action][Module][Feature] 组成,动作在前,特性在后 42 | 一系列同类函数,可加 MODULE_ 前缀,前缀单词全大写。 */ 43 | void InitDevice(void) /* 或者 DEVICE_Init() */ 44 | { 45 | s_deviceConfig.index = 1; 46 | s_deviceConfig.mode = kDeviceMode1; 47 | memset(s_deviceConfig.data, 5, sizeof(s_deviceConfig.data)); 48 | s_deviceConfig.isEnabled = true; 49 | } 50 | 51 | static uint32_t GetDeviceIndex(void) /* 或者 DEVICE_GetIndex() */ 52 | { 53 | return s_deviceConfig.index; 54 | } 55 | 56 | int main(void) 57 | { 58 | /* 局部变量定义应总是放在所在最小作用域(即最近的 {} 内)里的最前面 */ 59 | uint8_t i = 0; /* 一行代码仅定义一个变量 */ 60 | uint8_t j = 0; 61 | 62 | /* 永远不要使用 Tab 键(使用4个空格代替 Tab),需要以4个空格为单位的缩进 */ 63 | for (; i + j < 5;) 64 | { /* 不使用 K&R 风格花括号,左右括号都需要独占一行 */ 65 | i++; 66 | j++; 67 | } 68 | 69 | while (1) 70 | { 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /checker/test/test_utf8.c: -------------------------------------------------------------------------------- 1 | 2 | #include "template.h" 3 | /******************************************************************************* 4 | * Definitions 5 | ******************************************************************************/ 6 | 7 | #define MAX_devices0 (128U) 8 | #define MAX_devices1(a, b) (a+b) 9 | #define _MAX_DEVICES2 (128U) 10 | 11 | enum device_mode0 12 | { 13 | kDeviceMode0 = 0x00U, 14 | }; 15 | 16 | enum _DEVICE_mode1 17 | { 18 | kDeviceMode0 = 0x00U, 19 | }; 20 | 21 | typedef enum _device_mode2 22 | { 23 | kDeviceMode0 = 0x00U, 24 | } _device_mode2_t; 25 | 26 | typedef enum _device_mode3 27 | { 28 | kDeviceMode0 = 0x00U, 29 | } DEVICE_mode3_t; 30 | 31 | typedef enum _device_mode4 32 | { 33 | kDeviceMode0 = 0x00U, 34 | } DEVICE_mode4; 35 | 36 | typedef enum _device_mode5 37 | { 38 | deviceMode0 = 0x00U, 39 | } device_mode5_t; 40 | 41 | typedef enum _device_mode6 42 | { 43 | kDeviceMode0 = 0x00U, 44 | kDeviceMode1, 45 | kdeviceMode2 = 0x02U, 46 | } device_mode6_t; 47 | 48 | struct device_config0 49 | { 50 | uint32_t index; 51 | }; 52 | 53 | struct _DEVICE_config1 54 | { 55 | uint32_t index; 56 | }; 57 | 58 | typedef struct _device_config2 59 | { 60 | uint32_t index; 61 | } _device_config2_t; 62 | 63 | typedef struct _device_config3 64 | { 65 | uint32_t index; 66 | } DEVICE_config3_t; 67 | 68 | typedef struct _device_config4 69 | { 70 | uint32_t index; 71 | } DEVICE_config4; 72 | 73 | typedef struct _device_config5 74 | { 75 | uint32_t Index; 76 | } device_config5_t; 77 | 78 | typedef struct _device_config6 79 | { 80 | uint32_t index; 81 | uint32_t mo_de; 82 | } device_config6_t; 83 | 84 | /******************************************************************************* 85 | * Variables 86 | ******************************************************************************/ 87 | 88 | uint32_t g_deviceIndex0, g_deviceIndex1; /* fake comment. */ 89 | uint32_t *deviceIndex2 = 0; 90 | uint32_t *deviceIndex3 \ 91 | = 0; 92 | uint32_t **deviceIndex4; 93 | static uint32_t deviceIndex5 = 0; 94 | uint32_t deviceIndex6[100]; 95 | uint32_t g_DeviceIndex7; 96 | uint32_t g_device_index8; 97 | uint32_t g__deviceIndex9; 98 | uint32_t g_2deviceIndex10; 99 | 100 | static device_config_t deviceConfig = { /* fake comment. */ 101 | #if defined(MAX_DEVICES) 102 | .index = MAX_DEVICES, 103 | #else 104 | .index = 1, 105 | #endif 106 | .mode = 2, 107 | }; 108 | 109 | /******************************************************************************* 110 | * Prototypes 111 | ******************************************************************************/ 112 | 113 | /******************************************************************************* 114 | * Code 115 | ******************************************************************************/ 116 | 117 | static uint32_t getDeviceIndex0(uint8_t arg0, 118 | uint8_t arg1) 119 | { 120 | return s_deviceConfig.index; 121 | } 122 | 123 | static uint32_t Get_DeviceIndex1(void) 124 | { 125 | return s_deviceConfig.index; 126 | } 127 | 128 | static uint32_t DEVICE_getIndex2(void) { 129 | return s_deviceConfig.index; 130 | } 131 | 132 | static uint32_t DEVICE_Get_Index3(void) 133 | { 134 | return s_deviceConfig.index; 135 | } 136 | 137 | static uint32_t _DEVICE_GetIndex4(void) 138 | { 139 | return s_deviceConfig.index; 140 | } 141 | 142 | static uint32_t _device_get_index5(void) 143 | { 144 | return s_deviceConfig.index; 145 | } 146 | 147 | int main(void) 148 | { 149 | uint8_t i = 0; 150 | uint8_t j = 0; 151 | 152 | for (; i + j < 5;) 153 | { 154 | i++; 155 | j++; 156 | } 157 | 158 | while (1) 159 | { 160 | } 161 | } 162 | 163 | -------------------------------------------------------------------------------- /checker/test/test_utf8.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _test_utf8_h_ 3 | #ifndef TEST_UTF8_H 4 | #ifndef _TEST_UTF8_ 5 | 6 | #include 7 | #include 8 | #include 9 | /******************************************************************************* 10 | * Definitions 11 | ******************************************************************************/ 12 | 13 | #define MAX_devices4 (128U) 14 | #define MAX_devices5(a, b) (a+b) 15 | #define _MAX_DEVICES6 (128U) 16 | 17 | /******************************************************************************* 18 | * API 19 | ******************************************************************************/ 20 | 21 | #endif 22 | #endif 23 | #endif 24 | 25 | -------------------------------------------------------------------------------- /checker/test/中文/test_utf8.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _test_utf8_h_ 3 | #ifndef TEST_UTF8_H 4 | #ifndef _TEST_UTF8_ 5 | 6 | #include 7 | #include 8 | #include 9 | /******************************************************************************* 10 | * Definitions 11 | ******************************************************************************/ 12 | 13 | #define MAX_devices4 (128U) 14 | #define MAX_devices5(a, b) (a+b) 15 | #define _MAX_DEVICES6 (128U) 16 | 17 | /******************************************************************************* 18 | * API 19 | ******************************************************************************/ 20 | 21 | #endif 22 | #endif 23 | #endif 24 | 25 | -------------------------------------------------------------------------------- /coding_style.md: -------------------------------------------------------------------------------- 1 | # mcux_sdk_coding_style 2 | 3 | ### 1.命名 4 | 5 | #### 1.1 变量 6 | 7 | 变量命名使用 CamelCase (小骆驼峰法),即第一个单词以小写字母开始,第二个单词以及后面的每一个单词的首字母大写,例如 myVariableName 8 | 9 | > * 作用域可在文件外的全局变量加 g\_ 前缀,如 g\_myVariableName 10 | > * 使用 static 修饰的全局变量加 s\_ 前缀,如 s\_myVariableName 11 | > * 局部变量不加任何前缀,如 myVariableName 12 | > * 其他如 volatile, const 修饰或指针型变量,无需任何特殊表示 13 | > * 命名中的大部分单词都不要缩写,除非是相当流行的缩写,如 init 或 config 14 | 15 | #### 1.2 宏 16 | 17 | 宏命名使用下划线命名法,单词全大写,例如 MY_MACRO_NAME 18 | 19 | #### 1.3 枚举 20 | 21 | 枚举类型的命名混合了多种命名法,且加了一些特殊前后缀 22 | 23 | > * 枚举类型名使用下划线命名法,单词全小写,且以下划线开头 24 | > * 枚举元素名使用小骆驼峰法,但统一加 k 前缀 25 | > * 可用 typedef 重命名枚举类型名,使用下划线命名法,但需加 \_t 后缀 26 | > * 枚举变量名使用小骆驼峰法 27 | 28 | ```C 29 | typedef enum _my_enumeration_name 30 | { 31 | kMyEnumerator0 = 0x00U, 32 | kMyEnumerator1 = 0x01U, 33 | 34 | kMyEnumeratorEnd = 0x02U, 35 | } my_enumeration_name_t; 36 | 37 | static my_enumeration_name_t s_myEnumVariableName; 38 | ``` 39 | 40 | #### 1.4 结构体 41 | 42 | 结构体类型的命名混合了多种命名法,且加了一些特殊前后缀 43 | 44 | > * 结构体类型名使用下划线命名法,单词全小写,且以下划线开头 45 | > * 结构体成员名使用小骆驼峰法 46 | > * 可用 typedef 重命名结构体类型名,使用下划线命名法,但需加 \_t 后缀 47 | > * 结构体变量名使用小骆驼峰法 48 | 49 | ```C 50 | typedef struct _my_struct_name 51 | { 52 | uint32_t myStructMember0; 53 | uint32_t myStructMember1; 54 | } my_struct_name_t; 55 | 56 | static my_struct_name_t s_myStructVariableName; 57 | ``` 58 | 59 | #### 1.5 函数 60 | 61 | 函数命名使用 Pascal (大骆驼峰法),即把变量名称的第一个字母也大写,例如 MyFunctionName() 62 | 63 | > * 函数命名可由 [Action][Module][Feature] 组成,动作在前,特性在后。如 InitDeviceClock() 64 | > * 一系列同类函数,可加 MODULE\_ 前缀,前缀单词全大写。如 SD 卡操作的系列函数,可为 SD_PowerOnCard()、SD_PowerOffCard() 65 | 66 | Note: 但是也可以接受 Linux 函数命名风格,即下划线命名法,单词全小写,例如 my_function_name() 67 | 68 | ### 2.代码体 69 | 70 | #### 2.1 排版 71 | 72 | > * 永远不要使用 Tab 键(使用 4 个空格代替 Tab),需要以 4 个空格为单位的缩进 73 | > * 换行符应使用 "unix"(LF),而不是windows(CR + LF) 74 | > * 文件结尾需空一行 75 | 76 | #### 2.2 花括号 77 | 78 | 不使用 K&R 风格花括号,左右括号都需要独占一行 79 | 80 | #### 2.3 局部变量定义 81 | 82 | 局部变量定义应总是放在所在最小作用域(即最近的 {} 内)里的最前面,并且一行代码仅定义一个变量 83 | 84 | ```C 85 | void MyFunctionName(void) 86 | { 87 | uint8_t myVariableName0; 88 | uint8_t myVariableName1; 89 | 90 | /* 代码体 */ 91 | 92 | for (;;) 93 | { 94 | uint8_t myVariableName2; 95 | 96 | /* 代码体 */ 97 | } 98 | } 99 | ``` 100 | 101 | #### 2.4 数字 102 | 103 | 代码中所有无符号整型数字,均应加 "U" 后缀 104 | 105 | ```text 106 | Hex: 0x1234ABCDU 107 | Dec: 1234U 108 | ``` 109 | 110 | #### 2.5 注释 111 | 112 | 仅使用 /\* \*/ 来注释 113 | 114 | ```C 115 | /* 注释风格1,单独占一行 */ 116 | uint8_t i = 0; 117 | 118 | for (; i < 5;) 119 | { 120 | i++; /* 注释风格2,与代码共享一行 */ 121 | } 122 | ``` 123 | 124 | #### 2.6 条件编译 125 | 126 | \#endif 后面需要加如下注释 127 | 128 | ```C 129 | #if MY_MACRO_NAME 130 | 131 | /* 代码体 */ 132 | 133 | #endif /* MY_MACRO_NAME */ 134 | ``` 135 | 136 | #### 2.7 头文件保护宏 137 | 138 | 任何一个 .h 文件都需要包含下面格式的头文件保护宏代码,宏的命名与头文件名保持一致。如文件名为 hello\_world.h,则宏名为 \_HELLO\_WORLD\_H\_ 139 | 140 | ```C 141 | #ifndef _HEADER_FILENAME_ 142 | #define _HEADER_FILENAME_ 143 | 144 | /* 头文件内容 */ 145 | 146 | #endif /* _HEADER_FILENAME_ */ 147 | ``` 148 | 149 | ### 3.整体模板 150 | #### 3.1 源文件(.c) 151 | ```C 152 | /* 包含头文件代码 */ 153 | 154 | #include "template.h" 155 | 156 | /******************************************************************************* 157 | * Definitions 158 | ******************************************************************************/ 159 | 160 | /* 私有(仅本源文件内使用)宏、枚举、结构体的定义 */ 161 | 162 | #define MAX_DEVICES (128U) 163 | 164 | /******************************************************************************* 165 | * Variables 166 | ******************************************************************************/ 167 | 168 | /* 所有全局变量(外部,静态,常量,指针)的定义 */ 169 | 170 | uint32_t g_deviceIndex = 0; 171 | 172 | static device_config_t s_deviceConfig; 173 | 174 | const uint32_t g_maxDevices = MAX_DEVICES; 175 | 176 | static volatile uint8_t *s_deviceData; 177 | 178 | /******************************************************************************* 179 | * Prototypes 180 | ******************************************************************************/ 181 | 182 | /* 内部函数(即 static 修饰)的声明 */ 183 | 184 | static uint32_t GetDeviceIndex(void); 185 | 186 | /******************************************************************************* 187 | * Code 188 | ******************************************************************************/ 189 | 190 | /* 所有函数(外部,内部)的定义 */ 191 | 192 | void InitDevice(void) 193 | { 194 | s_deviceConfig.index = 1; 195 | s_deviceConfig.mode = kDeviceMode1; 196 | memset(s_deviceConfig.data, 5, sizeof(s_deviceConfig.data)); 197 | s_deviceConfig.isEnabled = true; 198 | } 199 | 200 | static uint32_t GetDeviceIndex(void) 201 | { 202 | return s_deviceConfig.index; 203 | } 204 | 205 | int main(void) 206 | { 207 | InitDevice(); 208 | g_deviceIndex = GetDeviceIndex(); 209 | 210 | while (1) 211 | { 212 | } 213 | } 214 | 215 | ``` 216 | 217 | #### 3.2 头文件(.h) 218 | 219 | ```C 220 | /* 221 | * Copyright xxx 222 | * All rights reserved. 223 | * 224 | * xxx License 225 | * 226 | * Revision History: 227 | * v1.0 - Description 228 | */ 229 | 230 | #ifndef _TEMPLATE_H_ 231 | #define _TEMPLATE_H_ 232 | 233 | /* 包含头文件代码 */ 234 | 235 | #include 236 | #include 237 | #include 238 | 239 | /******************************************************************************* 240 | * Definitions 241 | ******************************************************************************/ 242 | 243 | /* 公共(可被其他源文件使用)宏、枚举、结构体的定义 */ 244 | 245 | enum _device_mode 246 | { 247 | kDeviceMode0 = 0x00U, 248 | kDeviceMode1 = 0x01U, 249 | 250 | kDeviceModeEnd = 0x02U, 251 | }; 252 | 253 | typedef struct _device_config 254 | { 255 | uint32_t index; 256 | uint32_t mode; 257 | uint8_t data[16]; 258 | bool isEnabled; 259 | } device_config_t; 260 | 261 | /* 外部全局变量的声明 */ 262 | 263 | extern uint32_t g_deviceIndex; 264 | 265 | extern const uint32_t g_maxDevices; 266 | 267 | /******************************************************************************* 268 | * API 269 | ******************************************************************************/ 270 | 271 | #if defined(__cplusplus) 272 | extern "C" { 273 | #endif /*_cplusplus*/ 274 | 275 | /* 外部函数(可加 extern 修饰)的声明 */ 276 | 277 | void InitDevice(void); 278 | 279 | #if defined(__cplusplus) 280 | } 281 | #endif /*_cplusplus*/ 282 | 283 | #endif /* _TEMPLATE_H_ */ 284 | 285 | ``` 286 | 287 | -------------------------------------------------------------------------------- /images/build_v0.5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JayHeng/MCU-CodingStyleChecker/f49469a977562b79c6c818571ba6d1275bb70f82/images/build_v0.5.PNG -------------------------------------------------------------------------------- /template.c: -------------------------------------------------------------------------------- 1 | /* 包含头文件代码 */ 2 | #include "template.h" 3 | /******************************************************************************* 4 | * Definitions 5 | ******************************************************************************/ 6 | 7 | /* 私有(仅本源文件内使用)宏、枚举、结构体的定义 */ 8 | 9 | /* 宏命名使用下划线命名法,单词全大写 */ 10 | #define MAX_DEVICES (128U) /* 无符号整型数字,均应加 "U" 后缀 */ 11 | 12 | /******************************************************************************* 13 | * Variables 14 | ******************************************************************************/ 15 | 16 | /* 所有全局变量(外部,静态,常量,指针)的定义 */ 17 | 18 | /* 变量命名使用 CamelCase (小骆驼峰法),即第一个单词以小写字母开始, 19 | 第二个单词以及后面的每一个单词的首字母大写 */ 20 | uint32_t g_deviceIndex = 0; /* 作用域可在文件外的全局变量加 g_ 前缀 */ 21 | static device_config_t s_deviceConfig; /* 使用 static 修饰的全局变量加 s_ 前缀 */ 22 | const uint32_t g_maxDevices = MAX_DEVICES; 23 | static volatile uint8_t *s_deviceData; /* volatile, const 修饰或指针型变量, 24 | 无需任何特殊表示 */ 25 | 26 | /******************************************************************************* 27 | * Prototypes 28 | ******************************************************************************/ 29 | 30 | /* 内部函数(即 static 修饰)的声明 */ 31 | 32 | static uint32_t GetDeviceIndex(void); 33 | 34 | /******************************************************************************* 35 | * Code 36 | ******************************************************************************/ 37 | 38 | /* 所有函数(外部,内部)的定义 */ 39 | 40 | /* 函数命名使用 Pascal (大骆驼峰法),即把变量名称的第一个字母也大写 41 | 函数命名可由 [Action][Module][Feature] 组成,动作在前,特性在后 42 | 一系列同类函数,可加 MODULE_ 前缀,前缀单词全大写。 */ 43 | void InitDevice(void) /* 或者 DEVICE_Init() */ 44 | { 45 | s_deviceConfig.index = 1; 46 | s_deviceConfig.mode = kDeviceMode1; 47 | memset(s_deviceConfig.data, 5, sizeof(s_deviceConfig.data)); 48 | s_deviceConfig.isEnabled = true; 49 | } 50 | 51 | static uint32_t GetDeviceIndex(void) /* 或者 DEVICE_GetIndex() */ 52 | { 53 | return s_deviceConfig.index; 54 | } 55 | 56 | int main(void) 57 | { 58 | /* 局部变量定义应总是放在所在最小作用域(即最近的 {} 内)里的最前面 */ 59 | uint8_t i = 0; /* 一行代码仅定义一个变量 */ 60 | uint8_t j = 0; 61 | 62 | /* 永远不要使用 Tab 键(使用4个空格代替 Tab),需要以4个空格为单位的缩进 */ 63 | for (; i + j < 5;) 64 | { /* 不使用 K&R 风格花括号,左右括号都需要独占一行 */ 65 | i++; 66 | j++; 67 | } 68 | 69 | while (1) 70 | { 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /template.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 20xx-20xx NXP 3 | * All rights reserved. 4 | * 5 | * SPDX-License-Identifier: BSD-3-Clause 6 | * 7 | * Revision History: 8 | * v0.1 - Initial Drop 9 | */ 10 | 11 | #ifndef _TEMPLATE_H_ 12 | #define _TEMPLATE_H_ 13 | /* 任何一个 .h 文件都需要包含上面格式的头文件保护宏,宏的命名与头文件名保持一致 */ 14 | 15 | /* 包含头文件代码 */ 16 | #include 17 | #include 18 | #include 19 | /******************************************************************************* 20 | * Definitions 21 | ******************************************************************************/ 22 | 23 | /* 公共(可被其他源文件使用)宏、枚举、结构体的定义 */ 24 | 25 | /* 枚举类型名使用下划线命名法,单词全小写,且以下划线开头。 26 | 枚举元素名使用小骆驼峰法,但统一加 k 前缀 */ 27 | enum _device_mode 28 | { 29 | kDeviceMode0 = 0x00U, 30 | kDeviceMode1 = 0x01U, 31 | kDeviceModeEnd = 0x02U, 32 | }; 33 | 34 | /* 结构体类型名使用下划线命名法,单词全小写,且以下划线开头。 35 | 结构体成员名使用小骆驼峰法 */ 36 | typedef struct _device_config 37 | { 38 | uint32_t index; 39 | uint32_t mode; 40 | uint8_t data[16]; 41 | bool isEnabled; 42 | } device_config_t; 43 | 44 | /* 外部全局变量的声明 */ 45 | 46 | extern uint32_t g_deviceIndex; 47 | 48 | extern const uint32_t g_maxDevices; 49 | 50 | /******************************************************************************* 51 | * API 52 | ******************************************************************************/ 53 | #if defined(__cplusplus) 54 | extern "C" { 55 | #endif /*_cplusplus*/ 56 | 57 | /* 外部函数(可加 extern 修饰)的声明 */ 58 | 59 | void InitDevice(void); 60 | 61 | #if defined(__cplusplus) 62 | } 63 | #endif /*_cplusplus*/ 64 | /* #endif 后面需要加如上注释 */ 65 | 66 | #endif /* _TEMPLATE_H_ */ 67 | --------------------------------------------------------------------------------