Стандарты кодирования OMR со временем развивались, и, подобно исходному коду, мы ожидаем, что они продолжат улучшаться. В результате старый исходный код может не полностью соответствовать самой последней версии стандартов. Тем не менее, как сообщество, наша цель — следовать стандартам, насколько это возможно. По мере обновления старого кода мы стремимся приблизиться к стандартам. Участники обязуются соблюдать правила во время проверки кода.
Исключения были и будут сделаны в экстремальных обстоятельствах, таких как большой вклад существующего кода, где принуждение к соблюдению может непреднамеренно привести к побочным эффектам в виде ошибок из-за ручного переписывания кода.
void
в списке параметров.
Правильно:int
myFunction(void)
{
statements;
}
Неправильно:
int
myFunction()
{
statements;
}
Обоснование:
Правильно:
int
myFunction(void) {
statements;
}
Неправильно:
int
myFunction(void)
{
statements;
}
Всегда используйте совпадающие открывающие и закрывающие фигурные скобки. Если используются #ifdef, убедитесь, что количество фигурных скобок по-прежнему совпадает.
Лучше:
if (
#ifdef FOO
condition1
#else
condition2
#endif
) {
statements;
}
Правильно:
#ifdef FOO
if (condition1) {
#else
if (condition2) {
#endif
statements;
}
Неправильно:
#ifdef FOO
if (condition1)
#else
if (condition2)
#endif
{
statements;
}
Все операторы if, for, while, do и другие управляющие операторы должны быть записаны с фигурными скобками.
Правильно:
if (foo) {
doSomething();
}
Неправильно:
if (foo) doSomething();
Обоснование. Все стили фигурных скобок имеют свои преимущества и недостатки; выбор одного из них является отчасти произвольным. Это то, что мы выбрали.
Общий стиль фигурных скобок позволяет:
Правильно:
switch (foo) {
case 1:
doCaseOne();
break;
case 2:
doCaseTwo();
break;
default:
doDefaultCase();
break;
}
Неправильно:
switch (foo) {
case 1:
doCaseOne();
break;
case 2:
doCaseTwo();
break;
default:
doDefaultCase();
break;
}
Правильно:
switch (foo) {
case 1:
doCaseOne();
break;
case 2:
doCaseTwo();
break;
default:
assertUnreachable();
}
Неправильно:
switch (foo) {
case 1:
doCaseOne();
break;
case 2:
doCaseTwo();
break;
}
Лучше (без провала):
switch (foo) {
case 1:
doCaseOne();
break;
case 2:
doCaseTwo();
doCaseThree();
break;
case 3:
doCaseThree();
break;
case 4:
case 5:
doCaseFourOrFive();
break;
default:
assertUnreachable();
}
Правильно:
switch (foo) {
case 1:
doCaseOne();
break;
case 2:
doCaseTwo();
/* FALLTHROUGH */
case 3:
doCaseThree();
break;
case 4:
case 5:
doCaseFourOrFive();
break;
default:
assertUnreachable();
}
Неправильно:
switch (foo) {
case 1:
doCaseOne(); break;
case 2:
doCaseTwo();
case 3:
doCaseThree(); break;
case 4:
case 5:
doCaseFourOrFive(); break;
}
Обоснование.
Правильно:
if (0 == value1) {
...
} else if (0 != value2) {
...
} else if ((value4 + 1) == value3) {
...
}
Неправильно:
if (value1 == 0) {
...
} else if (value2 != 0) {
...
} else if (value3 == (value4 + 1)) {
...
}
Правильно:
if (0 == helperFunction(count, count + 1, dataBlock)) {
...
}
Неправильно:
if (helperFunction(count, count + 1, dataBlock) == 0) {
...
}
Старайтесь избегать длинных условий. Можно ли переписать условие, чтобы оно было проще?
Когда... Неизбежно, форматируйте длинные условия с помощью «&&» или «||» в начале каждой строки и заканчивая «) {» на отдельной строке.
Используйте круглые скобки, чтобы избежать путаницы в порядке операций.
Правильно:
if ((value1 == option1)
&& ((value2a == option2) || (value2b == option2))
&& (value3 == option3)
) {
...
}
Неправильно:
if ((value1 == option1) &&
((value2a == option2) || (value2b == option2)) &&
(value3 == option3)) {
...
}
Никогда не объединяйте присваивание и проверку, за исключением цикла while. В цикле while всегда используйте явную проверку.
Правильно:
myPointer = allocateStructure();
if (NULL != myPointer) {
...
}
Неправильно:
if (myPointer = allocateStructure()) {
...
}
Правильно:
while (NULL != (cursor = getNext(iterator))) {
...
}
Неправильно:
while (cursor = getNext(iterator)) {
...
}
По возможности старайтесь избегать отрицательных условий. Положительные условия легче понять.
Правильно:
if (NULL == myPointer) {
doAnotherThing();
} else {
doOneThing();
}
Неправильно:
if (NULL != myPointer) {
doOneThing();
} else {
doAnotherThing();
}
Используйте следующий формат для сравнений (<, <=, >, или >=) вида (min <= value <= max), чтобы улучшить ясность.
Правильно:
if ((0 <= logLevelValue) && (logLevelValue <= 4)) {
Неправильно:
if ((logLevelValue >= 0) && (logLevelValue <= 4)) {
Все объекты и структуры должны передаваться по адресу (*), а не по ссылке или значению. Другие параметры, требующие обновления, также должны передаваться по адресу. Необъективные параметры, которые не обновляются, должны передаваться по значению. Аргументы C++ по ссылке (&) использовать нельзя. Параметры-указатели должны быть документированы с [in], [out] или [in,out], чтобы различать входные и выходные параметры.
Правильно:
void
myFunction(MyObject *arg);
Неправильно:
void
myFunction(MyObject& arg);
В качестве исключения из правила очень простые объекты C++ (например, базовые типы-обёртки) могут передаваться по значению.
Правильно:
void
myFunction(MyFlags arg);
Макросы должны быть короткими и консервативными. Если макрос занимает более 2–3 строк, рассмотрите возможность написания его в виде подпрограммы. Макросы должны быть «замкнутыми» и «независимыми от контекста». Не полагайтесь на знание имён переменных, определённых в контексте, в котором используется макрос. Если такое знание необходимо, используйте установочный макрос для объявления переменной (например, OMRPORT_ACCESS_FROM_OMRPORT()
).
Правильно:
#define FOO(v, x) ((v) = (x))
Неправильно:
#define FOO(x) ((v) = (x))
Не полагайтесь на рекурсивную оценку макросов. Хотя некоторые компиляторы поддерживают это, они не строго соответствуют спецификации ISO. Защищайте аргументы в макросах круглыми скобками.
Правильно:
#define FOO(x) ((x) + 1)
Неправильно:
#define FOO(x) x+1
Если макросу требуется область видимости, используйте do {} while (0)
вместо {}
. Это позволяет избежать нескольких трудно диагностируемых ошибок.
Правильно:
#define FOO(x) \
do { \
int32_t y = x; \
... \
} while (0)
Неправильно:
#define
``` **Использование макросов в C**
* Для многострочных макросов всегда начинайте тело макроса с новой строки.
Правильно:
```c
#define FOO(x) \
{ \
int32_t y = x; \
... \
}
Неправильно:
#define FOO(x) do { \
... \
} while (0)
Правильно:
#if defined(FOO)
return "foo";
#elif defined(BAR)
return "bar";
#else
return "other";
#endif
Неправильно:
#ifdef FOO
return "foo";
#else
#ifdef BAR
return "bar";
#else
return "other";
#endif
#endif
Правильно:
#define DOIT() doSomething()
#define MAX 23
Неправильно:
#define DOIT doSomething()
#define MAX() 23
Также см. Комментарий к директивам условной компиляции (if, #ifdef, #ifndef, else, elif, endif).
Обоснование
do {} while(0)
заставляет пользователей макроса следовать за ним точкой с запятой, что делает его более похожим на вызов функции.Возврат
Правильно:
return 0;
Неправильно:
return (0);
Правильно:
int32_t result = 0;
if (NULL != input) {
result = input->size;
}
return result;
Неправильно:
if (NULL == input) {
return 0;
} else {
return input->size;
}
Обоснование: return
— это ключевое слово, а не функция. return
— это неструктурированный переход, как goto
. Это может затруднить понимание потока кода.
Заголовочные файлы
Правильно:
#if !defined(FILENAME_HPP_)
#define FILENAME_HPP_
. . .
#endif /* !defined(FILENAME_HPP_) */
Правильно:
#include <string.h>
Неправильно:
#include "string.h"
Правильно:
#include "omr.h"
Неправильно:
#include <omr.h>
Правильно:
#include "ThisClass.hpp"
#include <float.h>
#include <string.h>
#include "omr.h"
#include "AnotherClass.hpp"
#include "HelperClass.hpp"
#include "OtherClass.hpp"
Обоснование: правильно защищённые заголовочные файлы предотвращают ошибки переопределения. Сортировка заголовков в алфавитном порядке помогает избежать случайного дублирования включений.
Указатели на константы
const
.const
, если они будут только считываться.Правильно:
void
doSomething(const SomeOptions *options)
{
const uint32_t optionsCount = options->count;
uint32_t optionIndex = 0;
for (; optionIndex < optionsCount; optionIndex++) {
...
Обоснование: const
устанавливает официальный договор между вызывающим и вызываемым. Компилятор может проверить соблюдение этого договора. Маркировка временных переменных const
помогает улучшить читаемость, явно различая истинные переменные и фиксированные значения. Использование const
может позволить большую оптимизацию.
Объявления переменных
...
}
* Не следует использовать комментарии для отключения части кода. Вместо этого используйте #if 0/#endif.
Правильно:
```c
#if 0
printf("Returning %d\n", rc);
#endif
Неправильно:
/* printf("Returning %d\n", rc);
*/
Правильно:
/**
* Определить количество виджетов, необходимое для изготовления
* желаемого количества гаджетов.
* @param[in] gadgetFactory фабрика гаджетов
* @param[in] gadgetsRequired требуемое количество гаджетов
* @return килограммы необходимых виджетов
*/
uint32_t
getWidgetsRequired(GadgetFactory *gadgetFactory, uint32_t gadgetsRequired)
{
...
Правильно:
typedef struct WidgetData {
uint32_t widgetSize; /**< Размер каждого виджета в байтах */
float widgetRate; /**< Скорость доставки виджетов в виджетах в миллисекунду */
} WidgetData;
Правильно:
#if defined(__cplusplus)
...
#endif /* defined(__cplusplus) */
Неверно:
#if defined (__cplusplus)
...
#endif
Правильно:
#if defined(A) || defined(B)
...
#elif !defined(C) /* defined(A) || defined(B) */
...
#else /* !defined(C) */
...
#endif /* defined(A) || defined(B) */
Правильно:
#if defined(A)
...
#else /* defined(A) */
...
#endif /* defined(A) */
Неверно:
#if defined(A)
...
#else /* !defined(A) */
...
#endif /* !defined(A) */
В запросе представлен текст технической направленности из области разработки и тестирования программного обеспечения. Основной язык текста запроса — английский. Имена классов начинаются с прописной буквы.
Имена классов пишутся в стиле «верблюжий регистр», например, WorkPackets.
Все классы должны иметь отдельные файлы .cpp и .hpp.
Файл .cpp можно опустить, если он будет пустым.
Правильно:
bool isValid(void);
if (isValid()) {
doit();
}
Неправильно:
bool checkValid(void);
if (checkValid()) {
doit();
}
Правильно:
BOOLEAN isValid(void);
if (isValid()) {
doit();
}
Неправильно:
BOOLEAN checkValid(void);
if (checkValid()) {
doit();
}
Правильно:
#define INVARIANT_SNIPPET_LENGTH 18
Обоснование:
typedef
всегда используется при объявлении перечисления, структуры и объединения в C.typedef
для этих элементов.struct
и typedef
.typedef
, чтобы определить указатель на структуру.Правильно:
typedef struct MyStruct {
char *string; /**<...
uint32_t value; /**<...
} MyStruct;
Неверно:
typedef struct {
char *string; /**<...
uint32_t value; /**<...
} MyStruct, *MyStructp;
Неверно:
typedef struct MyStructTag {
char *string; /**<...
uint32_t value; /**<...
} MyStruct;
Обоснование:
Предпочитайте использовать стандартные типы данных фиксированной ширины, такие как uint8_t
, int8_t
, uint32_t
и т. д. Следует избегать встроенных типов, таких как int
и long
. Они могут иметь разный размер на разных платформах.
Исключения могут быть сделаны при работе со стандартными библиотечными или специфическими для платформы функциями. В этом случае используйте соответствующие типы данных C, такие как char
или size_t
или DWORD
.
Также допускается исключение для указателей на строки C. Они должны быть char *
(или const char *
), а не uint8_t *
.
Используйте double
для данных с плавающей запятой, если нет веской причины использовать другой тип. Обоснование
Типы данных C различаются по размеру и знаку в зависимости от платформы. Использование чётко определённых типов позволяет избежать проблем с переносимостью в будущем.
Функции библиотеки
Обоснование
Предупреждения и ошибки
(uint32_t *)x = y;
1 << 36 /* undefined if sizeof(int) <= 4 */
. Используйте ((uint64_t)1) << 36
вместо этого.Обоснование
Обоснование
Перевод текста на русский язык:
Используйте #define или enums для присвоения символических имён константам вместо использования в коде литералов, кроме -1, 0, 1, 2.
Пример правильного использования:
enum {
TOO_TALL = -4,
MAX_HEIGHT = 7
}
if (height > MAX_HEIGHT) {
return TOO_TALL;
}
Пример неправильного использования:
if (height > 7) {
return -4;
}
Пример правильного использования:
typedef struct OMRInterface {
FUNCPTR doSomething;
} OMRInterface;
Пример неправильного использования:
typedef struct OMRInterface {
FUNCPTR doSomethingPtr;
} OMRInterface;
Это упрощает поиск ссылок на функцию.
Пример правильного использования:
assert(newValue >= oldValue);
uint32_t delta = newValue - oldValue;
Пример неправильного использования:
uint32_t delta = newValue - oldValue;
Всегда учитывайте деление на ноль; используйте утверждения, чтобы доказать, что это невозможно.
Пример правильного использования:
assert(0 != oldValue);
double ratio = (double)newValue / (double)oldValue;
Пример неправильного использования:
double ratio = (double)newValue / (double)oldValue;
Использование математики с плавающей запятой не запрещено. Избегайте неявного приведения вверх или вниз скалярных значений; вместо этого используйте явное приведение или измените типы данных, чтобы избежать приведения.
Пример правильного использования:
uint32_t count = getCount();
uint32_t size = getSize();
uint32_t averageSize = size / count;
Пример неправильного использования:
uint8_t count = getCount();
uint32_t size = getSize();
uint32_t averageSize = size / count;
При написании определения функции C++ отдельно от объявления используйте полностью квалифицированное имя, чтобы упростить поиск.
Неправильное использование:
namespace OMR {
Foo::Func(int*) ...
}
Правильное использование:
OMR::Foo::Func(int*)
Использование макросов, специфичных для платформы, и определений компиляции — это тема стандартизации. Сегодня используются следующие макросы для проверки того, какая платформа является хостом для компиляции OMR в трёх измерениях.
Макрос | Архитектура |
---|---|
J9ARM | ARM |
PPC | IBM Power Systems |
OMRZTPF | IBM z/TPF |
TODO: код для s390 | IBM System z |
X86 | x86 |
AMD64 | x86-64 |
Макрос | Битовая ёмкость |
---|---|
OMR_ENV_DATA64 | 64 |
В будущем мы хотели бы иметь флаги OMR_OS_xxx для операционной системы, аналогичные флагам OMR_ARCH_xxx.
Макрос | Операционная система |
---|---|
AIX | IBM AIX |
LINUX | GNU/Linux |
OMR_OS_WINDOWS | Microsoft Windows |
OSX | Apple OS X |
J9ZOS390 | IBM z/OS |
Правильное использование:
#if defined(LINUX) && !defined(OMRZTPF)
#if defined(OMR_OS_WINDOWS) && defined(OMR_ENV_DATA64)
#if defined( _AMD64_)
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )