├── .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 | 
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 |
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 |
--------------------------------------------------------------------------------