C-Сoding Standard. Russian Hungarian Notation

Технология разработки программного кода


Открыть/Скрыть все разделы содержания РВН стандарта

Данное руководство представляет собой программный стандарт под условным названием Русско Венгерская Нотация — РВН.

Нотация устанавливает набор правил, используемых при написании исходного кода на языке Си. Нотация обеспечивает:
    • поддержку единообразия стиля проектов на Си
    • устанавливает минимальные требования к информативности
    • позволяет всем разработчикам легко понимать код
    • упрощает вспомогательные задачи на базе общих/единых соглашений
    • упрощает работу с документацией, встраивая проектную документацию в код
    • понижает порог вхождения клиентов и новых сотрудников, предоставив точную документацию по коду и единый стиль.

Смешанный (mixed) РВН стандарт или стиль использовался при разработке ПО на более чем 15-ти языках. Этот документ рассматривает аспекты применения стандарта при программировании на С и С++. Областью применения данного стандарта является стиль программирования. Общий стиль способствует повышению производительности труда, улучшает переносимость и уменьшает количество возможных ошибок. Стандарт не охватывает все вопросы, но пытается объединить правила по стилю в единый набор, который должен подходить для многих проектов на Си, хотя некоторые его части ориентированы на определенные системы (embedded apps, boots, drivers, kernels и пр.). Правила нотации не охватывают все ситуации. Отсюда технология РВН — это все еще развивающийся подход и вы можете внести свою лепту в его развитие. РВН стандарт сам по себе не является догмой, но отдельные организации или команды могут взять его за основу. Многие из выбранных в стандарте стилей условно произвольны. Тем не менее, смешанный стиль кодирования сложнее поддерживать, чем плохой стиль кодирования. В случае наличия противоречий при рефакторинге уже существующего кода лучше следовать стилю (отступы, интервалы, комментарии, соглашения об именах) текущего проекта, чем слепо следовать нотации РВН . Тем более, что такой подход также разрешен и приветствуется в самом РВН стандарте. Близкими к РВН являются такие смешанные стили как: SEI CERT C Coding Standard и MISRA. При этом РВН строже SEI-CERT и гибче чем MISRA. Правила и рекомендации по написанию РВН-кода перекликаются с этими и другими смешанными и несмешанными стандартами и системами классификаций, такими как: FreeRTOS, Google C++ Style, Mozilla Coding Style, GNOME C Coding, Uber Go Style Guide, Indian Hill C Style and Coding, Linux kernel coding style и др.

РВН = snake_case + lowerCamelCase + CamelCase

РВН стиль — это смесь стандартов оформления кода, применяемых в языках: C Linux, C++/VC++, C#, WinAVR, Java, JavaScript, PHP, Ruby, VB/VBA/Basic, Perl, Delphi/Pascal, Algol, SQL, EL76, MASM, AVR-ASM, Bash/Sh, NDOS. и других. Он разрешает все, что ведет к компактности и читабельности кода и подходит для разработчиков предпочитающих как snake_case, так и lowerCamelCase или CamelCase стили.

Стиль snake_case нагляднее, CamelCase компактнее, lowerCamelCase еще более компактен. В РВН вы сможете воспользоваться преимуществами все трех стилей одновременно там, где это выгодно.

В принципе, гибкость РВН позволяет вам писать код в любом стиле. Однако слово «любой» не означает «произвольный» и поэтому лучше все же придерживаться тех правил, которые описаны ниже.

Постановка задачи

Для любого программного проекта (особенно для большого) очень важен стиль разработки, который определяет способы форматирование и размещение кода.

Часто начинающие программисты не обращают внимания на стиль разработки. Реализовав один небольшой проект, они считают, что уже стали профи, для коих никакие стандарты не писаны.

Но большие проекты развиваются совсем по другим законам, чем малые. И если не соблюдать стандарты, то через некоторое время (набрав критическую массу) большой проект становится практически неуправляемым.

Задача РВН-технологии предотвратить такое развитие событий и придать любому проекту единообразие. РВН делает код максимально лёгким к восприятию, минимизирует нагрузку на память и зрение программистов, а также вводит правила и соглашения, которые облегчают как написание кода, так и его редактирование

Использование РВН позволит вам добиться быстрого понимания кода в совокупности с его же (кода) максимальной краткостью и информативностью. Говоря иначе, код будет понятен с первого беглого взгляда.

В итоге, если над большим проектом работает сразу несколько разработчиков, им становится легче разбираться в исходном коде и понимать друг друга.

Почему так важен стиль разработки?

Стиль разработки кода — это не мода, не каприз и не прихоть проджект-менеджеров, а актуальная необходимость, продиктованная существующей практикой. А именно:

1. Хороший стиль на порядок улучшает качество кода.

2. Одинаковость стиля повышает производительность разработки.

3. В конечном итоге (пусть даже вначале это кажется мистикой), но если вы будете придерживаться слаженного стиля программирования, плюс выбирать правильные имена, то вы наделите себя и других властью над кодом.

Иногда говорят, что стиль написания исходного кода не важен, потому что он не влияет на скомпилированный объектный код. Однако для любого программного проекта (особенно при задействовании нескольких разработчиков) важна слаженность стиля и именно при слаженности стиля группа разработчиков чувствует себя командой.

Слаженность включает в себя одинаковость восприятия, что ведет к упрощению чтения, к избежанию путаницы и дает надежду на то, что и в будущем стиль останется одинаковым.

Это приводит к увеличению количества разработчиков, которые смогут нормально читать ваш код и увеличивает объем кода, который они смогут интуитивно понимать. Для большого проекта- чем больше будет внимательных глаз, тем лучше.

В идеале слаженность стиля должна приводить к ситуации, когда программисту для заключения о корректности работы какой-либо функции хватало бы знакомства только с участком кода, отвечающим за выполнение этой функции, то есть смысл кода должен быть виден из самого программного кода без необходимости изучать контекст.

Цели и задачи РВН

РВН стиль использовался во множестве больших проектов и, как стандарт, по-настоящему проверен временем. Он не является проприетарным стандартом и подразумевает возможные дополнения и расширения.

Одна из главных задач РВН: повысить информативность кода за счёт визуального оформления элементов программы. В следующих главах описаны основные правила и приемы, которые вы сможете использовать при разработке любых проектов в стиле РВН.

РВН — не просто стандарт или кодекс хороших манер программиста. Разработчики, пишущие в стиле РВН, находят в нём еще и мощную философскую подоплеку, которая обеспечивает РВН системность в реализации всех поставленных целей.

Суть технологии РВН состоит в соблюдении следующих ключевых концепций:
• модульность
DRY
• соглашения по программированию
• автодокументирование
• соглашения об именах
• соглашения по форматированию кода

Модульность позволяет изолировать независимые части кода друг от друга.

DRY означает: Don’t Repeat Yourself, то есть Не допускайте повторений. Другими словами, любая порция кода или сведений о системе должна быть размещена лишь в одном месте.

Соглашения по программированию это квинтэссенция профессиональных технологий, методологий и опыта. Их задача заключается в определении программных подходов, приёмов и правил используемых при разработке больших проектов.

Автодокументирование (автоматическое документирование) обеспечивает механизм и поддерживает специальный синтаксис для генерации документации на ПО прямо из исходных текстов.

Определяющими являются соглашения об именах (включают соглашения по именованию и написанию). Их суть заключается в том, чтобы сделать код более коротким и ясным.

Целью соглашений по форматированию является достижение максимальной читабельности написанного кода.

Разработчики, перешедшие на РВН , очень быстро отмечают положительные изменения. В один прекрасный момент они вдруг обнаруживают, что работать стало намного проще, проект сам выстраивается как надо, а все хорошие идеи легко находят свое воплощение.

У РВН есть вообще что-то такое, что трудно поддается описанию. У вас возникает чувство, что вы на правильном пути. Разумеется, пока вы не начнете писать код в стиле РВН , вам придется поверить нам на слово.

Если с помощью РВН добиться ясности кода не удаётся (код слишком сложен), то используйте комментарии. Если и это не помогает, то скорее всего алгоритм или код нужно пересмотреть и переписать заново.

Обзор РВН

Стандарт РВН определяет и описывает:
• способ организации программы в целом и отдельных модулей в частности
• способ описания файлов, функций и фрагментов кода
• соглашения об именах
• стиль комментариев и использование документирующих комментариев
• стиль написания логических и арифметических выражений
• использование скобок и пробелов
• использование ассемблерных вставок
• внедрение объектно-ориентированного подхода
• правила по использованию и разделению ресурсов
• поддержку и реализацию исключений
• написание переносимого кода
• и пр.

При именовании РВН позволяет использовать (и/или не использовать) следующее:
• кодирование типа переменной в её идентификаторе (венгерская нотация)
• суффиксы и регистр символов (нижний, верхний, верблюжий CamelCase стиль)
• знаки подчёркивания для разделения слов

РВН стандарт подразумевает:
• модульность
• исключение дублирующего кода
• отсутствие магических чисел
• ограничение размера кода по горизонтали
• ограничение размера кода по вертикали (размер в один экран)
• и многое другое

Соглашения по именованию

Выбирайте правильно имена.
Или как вы яхту назовете, так она и поплывет

Имена — сердце программирования. Имя является результатом продолжительного осмысления среды, в котором живёт тот или иной объект. Только тот разработчик, который понимает систему в целом, может дать объекту имя, полностью вписывающееся в концепцию создаваемой системы.

Если имя подобрано правильно, то тогда всё становится на свои места:
- отношения между объектами будут ясны
- значения легко угадываются
- все человеческие ожидания и мотивировки срабатывают так, как хотелось бы

В РВН допустимы имена в верблюжьей lowerCamelCase нотации. При этом lower можно опускать (CamelCase). Примеры:

                                            
aNODE
aLoopIndexes
Next
getLoopIndexes()
ShowBugs()
CDog

В РВН допустимы имена в змеиной snake_case нотации. При этом snake можно опускать. Примеры:


pci_conf_s
size_t
loop_indexes
loop_indexes_u
next
last
read
get_loop_indexes()
show_bugs()
u64
s64
u64

В рамках РВН разрешено ограничено использовать так называемую венгерскую запись ( Hungarian Notation ) в виде однобуквенных префиксов и/или постфиксов. Введение/поддержка однобуквенных префиксов и постфиксов позволяет обеспечить максимальную краткость имен идентификаторов при их же максимальной информативности.

Однако назвать переменную именем idx или даже i — это очень хорошо, но при условии, что будет понятно назначение этой переменной.

Имена могут включать общепринятые сокращения: или как часть имени, или в виде известного/устоявшегося/принятого префикса/постфикса. При этом, имена должны быть наглядными. Если глобальной функции присвоить имя acpu(), то это может привести к путанице. Более подходящим будет имя:

   get_active_cpu() 
   getActiveCPU 
или 
   getActiveCpu

Смешивать разные нотации в имени не рекомендуется, хотя и не запрещено (например если идентификатор создается в одной нотации, а объект к которому он применяется уже существует в другой тотации) .

Примеры неправильных имен:


a_Loop_indexes
a_LoopIndexes_s
neXt
indexeS
Get_loop_indexes()
show_Bugs()

Смешанные Camel + Snake стили кодирования, такие, как MISRA и РВН позволяют создавать на их основе собственные корпоративные стандарты, и таким образом обеспечивают для разработчиков различного встраиваемого ПО достаточную степень свободы в условиях унификации внешнего вида программ, делая их более читабельными и понятными.

За счет чего и как это происходит

1). Camel стиль практически универсален и компактен. Snake стиль более читабелен, но менее компактен. При РВН-кодировании вы можете воспользоваться преимуществами обоих стилей. Подробнее о преимуществах и сравнение стилей смотрите тут.

2). Де-юре смешанный snake+Camel стиль сегодня уже применяется во множестве известных проектов, например: MicroChip, OpenSSL, OpenTitan, TianoCore, Tuxera и во многих других. При этом, де-факто смешанный стиль используется в таких проектах, как Linux, U-BOOT, CoreBoot, BareBox, ПНС МЦСТ и пр. И если кто-то будет вам заявлять иное, то в обратном очень легко убедиться. Для этого просто скачайте c GitHub и откройте исходный код этих проектов! Примеры см. ниже. А отсюда — использование смешанного стиля в РВН позволяет свободно (без нарушения соглашений и ввода исключений) портировать/интегрировать код из различающихся по стилю систем.

3). В РВН разрешено применять заранее определенные стандартом, однобуквенные префиксы/постфиксы и программные сокращения. При этом РВН — это одновременно и широкий и гибкий, но вместе с тем крайне жесткий стиль со множеством ограничений. РВН требует соблюдения ряда строгих правил, кои детально описаны в данной документации.

4). В целом РВН позволяет (на основании правил) использовать (там и когда это нужно) все преимущества разных стилей. В РВН вообще: а) считается полезным все, что приводит к кратности написания и быстрому пониманию кода. И б) В РВН считается контрпродуктивным и вредным все (любые правила и ограничения), что противоречит принципу а). Конечно если последнее не нарушает безопасность и надежность кода.

5). Использование чистого snake стиля имело смысл в эпоху отсутствия развитых ( продвинутых ) интегрированных сред разработки (IDE). Отсюда бессмысленно придерживаться догм, которые только усложняют код, и не считаться с прогрессом в инструментах разработки, достигнутым за последние тридцать лет.

6). Кроме того, разработчики оборудования не обязаны считаться с правилами разработки ПО и часто создают свои datasheet’s в смешанном стиле. При этом, каждая embeded system должна прежде всего соответствовать (отвечать) целевому «железу». Поскольку большая часть кода embeded system посвящена настройке/инициализации целевого оборудования, то в результате не-применения (отсутствия) смешанного стиля исходники embeded system превращаются в сплошной «плохой код», состоящий из множества исключений и противоречий любому not-mixed style. Примеры кода в стиле РВН и других смешанных стилях см. тут.

Синтаксис венгерской нотации сводится к тому, что имена идентификаторов начинаются или заканчиваются заранее оговоренными префиксами и постфиксами. При этом ни само наличие префикса и/или постфикса, ни их написание не являются требованием языка программирования С.

Венгерская нотация является широко используемым внутренним стандартом фирмы Microsoft. Использование венгерской нотации делает код значительно компактнее, что позволяет программистам разрабатывать ПО в более короткие сроки. Её главный недостаток в том, что запись нескольких префиксов подряд делает имена идентификаторов менее понятными и, таким образом, сильно ухудшается читаемость кода.

РВН vs Венгерская нотация

Все префиксы и постфиксы в РВН заранее определены, легко запоминаются и в отличии от венгерской нотации состоят из одного символа, к которому может добавляться (если нужно) знак подчеркивания. Таким образом, РВН устраняет основной недостаток венгерской нотации, сохраняя её преимущества. Обычно префиксы и постфиксы применяются для кодирования типа или вида переменной в её имени или указания в имени принадлежности к области действия.

Зачем это нужно:
1). Чтобы код стал существенно компактнее
2). Чтобы было сложнее ошибиться в выборе названия функции или переменной
3). Чтобы само название в сжатой форме давало главную информацию о переменной или функции (например, тип переменной, является ли она глобальной, особенности функции – возвращаемое значение, является ли она методом или принадлежит к некой области/группе и пр.)

В РВН можно использовать не больше одного однобуквенного префикса в начале и не больше одного однобуквенного постфикса в конце имени. Также не рекомендуется (но и не запрещено) использовать префикс и постфикс в имени одновременню. Имя не должно включать больше трех (а лучше двух) слов без учета префикса и постфикса. Имя может начинаться с ID модуля/пакета/класса в верхнем регистре, отделённого символом подчёркивания.

Примеры неправильных имен:


ai_Loop_indexes
a_i_Loop_indexes
a_LoopIndexes_s_e
aiIndexeS
loop_indexes_ai()
PCI_rescanNODEaItem_t
ui64

Имена переменных

Имя переменной должно полно и точно описывать сущность, представляемую переменной.

Имя следует выбирать читабельным, содержательным и по возможности коротким. В основе имени переменной должны лежать существительное (id, name, count, myID, last_name, coreCount).

Суть переменной Правильно Неправильно
Контрольная сумма check_sum KS, x, x1, x2, Temp
Число строк на странице lines_per_page LPP, x, x1, x2
Текущая дата current_date current, x, x1, x2
Скорость поезда train_velocity x, x1, x2
Идентификатор identifier, id x, x1, x2, idnt
Массив Идентификаторов aIdentifiers, aID ax, ax1, ax2, aidnt

 

Имена KS, LPP неудачны потому, что не являются общепринятыми сокращениями, вследствие чего не описывают сущность переменной.

Имя Current для переменной «Текущая дата» является неудачными, так как не полно и не точно описывает суть переменной.

Имена x, x1 и x2 традиционно представляют собой неизвестное количество чего-либо, что в данных случаях не является сутью переменной.

Имя переменной необходимо подбирать из слов английского языка. Допускаются сокращения, не затрудняющие читабельность и понимание сути переменной. Лучше, чтобы эти сокращения были из числа общепринятых. Не следует писать русские слова и аббревиатуры английскими буквами.

Суть переменной Правильно Неправильно
Код клавиши key_code knopka
Ширина width shirina
Высота height visota

 

Для терминов, обозначающих механизмы, системы, их элементы, нужно использовать технически правильный перевод. При необходимости следует обращаться к специализированным словарям. Следует соблюдать единство английской терминологии.

Суть переменной Правильно Неправильно
Ствол орудия barrel tube, trunk
Подача в системе заряжания пушки feed supply
Подача электропитания power_supply feed

 

В качестве индексов простых циклов следует использовать переменные i, j и k и пр.


for ( i = first_item; i < last_item; i++ )
{
    data[ i ] = 0;
}

Если цикл является вложенным, индексу цикла рекомендуется присвоить полное осмысленное имя.

for ( team_index = 0; team_index < team_count; team_index++ )
{
    for ( evn_index=0; evn_index < evn_count[ team_index ]; evn_index++ )
    {
        score[ team_index ][ event_index ] = 0;
    }
}

Правильный выбор имён индексов циклов позволяет избежать путаницы – использования i вместо j и наоборот. Кроме того, это облегчает понимание операций над массивами.

Например запись:

cpus[ node_index ][ core_index ]

более информативна, чем запись:

cpus[ i ][ j ]

Логическим переменным следует давать имена, подразумевающие значения true или false.

Такими типичными именами логических переменных являются:

done    - признак завершения цикла или другой операции)
error   - признак ошибки
found   - признак определения того, что обнаружено искомое значение
success - ok, признак успешности завершения операции) и т.п. 

Список примеров:

Суть переменной Правильно Неправильно
Операция завершена done flag
Операция завершена без ошибок success not_error

 

Следует использовать только утвердительные имена логических переменных, чтобы избежать появления инструкций типа

if ( !not_error )

Именовать константы перечисления следует согласно правилам именования переменных. При этом к каждой константе перечисления можно добавлять в качестве префикса имя самого перечисления или имя типа.

Правильно Но можно и так
typedef enum :
{
COLOR_RED,
COLOR_GREEN,
COLOR_BLUE
} Color;
typedef enum :
{
RED,
GREEN,
BLUE
} Color;

 

Переменным, характеризующим состояние объекта, следует давать имена, которые лучше сравнивать со значениями перечислений или именованных констант.

Правильно Неправильно
char_type = PRINTABLE_CHAR;
 print_flag = 0x16;

 

В случае использования пары переменных, смысл использования которых прямо противоположен, их необходимо именовать словами-антонимами.

begin/end min/max visible/invisible
enabled/disabled next/previous source/target
first/last old/new up/down
locked/unlocked opened/closed add/delete

 

Подбор имён функций

Имя функции должно ясно и понятно описывать суть выполняемых действий, а также результат и все побочные эффекты, которые реализует функция.

Рекомендуется начинать имя функции с глагола (выполняемого функцией действя).

Суть функции Правильно Но можно и так
Вычислить контрольную сумму
 CalcCS()         
 CS()       
Вычислить контрольную сумму
 calcCS()         
Вычислить контрольную сумму
 calc_check_sum() 
Вычислить КС и записать в БД
 calcCsSaveToDB() 
CalcSaveCS()

 

Если функция вычисляет контрольную сумму и записывает её в базу данных, то такой функции (по правилу выше) следует дать имя сalculateCheckSumAndSaveToDataBase().

Такое имя получается слишком длинным и несуразным. Следовательно, не стоит создавать функции с побочными эффектами.

В именах функций следует избегать неоднозначных глаголов. Некоторые глаголы могут описывать практически любое действие. Имена функций вроде ProcessInput() ничего не говорят о конкретной работе функции.

В именах функций можно использовать описание возвращаемого значения.

Суть функции Имя функции
Вычислить косинус угла
 Cos()               
Получить значение текущего цвета
 getCurrentColor()   
Вычислить контрольную сумму
 CalculateCheckSum() 

 

Для имен функций без возвращаемого значения (процедур) нужно обязательно использовать формат «глагол + объект». Глагол должен отражать выполняемое процедурой действие над объектом.

Суть процедуры Имя процедуры
Вывести документ на печать
 PrintDocument()     
Получить значение текущего цвета
 GetCurrentColor()   
Получить значение текущего цвета
 getCurrentColor()   
Получить значение текущего цвета
 get_current_color() 
Вычислить контрольную сумму
 CalculateCheckSum() 
Вычислить контрольную сумму
 calcCheckSum()      
Вычислить контрольную сумму
 calc_check_sum()    

 

Если функция вычисляет какое-либо логическое выражение, то ей можно присвоить имя с префиксом Is.

IsReady()
is_ready()

В случае использования функций, выполняющих прямо противоположные действия, их необходимо именовать словами-антонимами.

add()/remove()         
 begin()/end()    
 create()/destroy()
Add()/Remove()         
 Begin()/End()    
 Create()/Destroy()
First()/Last()         
 Get()/Put()      
 Get()/Set()       
Increment()/Decrement()
 Insert()/Delete()
 Lock()/Unlock()   
Min()/Max()            
 Next()/Previous()
 Old()/New()       
Open()/Close()         
 Show()/Hide()    
 Source()/Target() 
Start()/Stop()         
 Up()/Down()      
                   

 

Подбор имён функций входящих/принадлежащих некой области

Рекомендуемый стиль:
[AREA-ID]_<глагол>_<цель>([параметры])

AREA-ID — в верхнем регисте
глагол — в нижнем регистре>
цель — в нижнем регистре

Пример:

PCI_fill_bridge( pci_node_t * node );  

 
Если функция статическая или используется только локально внутри Класса/Модуля/Пакета, то такой функции рекомендуется давать имя в змеином стиле. Пример:

fill_bridge( pci_node_t * node );  

 
Хотя обратное (из общих соображений стиля) тоже не запрещено. Если function-like макрос или функция глобальны для всего проекта, то имя такой функции или макроса рекомендуется начинать с заглавной буквы. Пример:

Echo
_Echo
ECHO  

 
Простые правила, а магия технологии заработала. Названия Си-файлов (*.c, *.h) — это имя сущности из DataSheet. Имя для Модуля/Класса/Пакета/Группы — таже сущность в верхнем регистре. Добавляем к имени Модуля известные глаголы init, set, get, put, let, show, плюс существительные целевых полей. И имена функций готовы. В результате — ваше ПО полностью отвечает железу и складывается такое ощущение, что программа пишет себя сама.

Соглашения по написанию

Написание имён переменных

Переменные следует писать либо строчными буквами, либо применять к ним lowerCamelCase и/или CamelCase стиль.

Имя переменной может включать:
• не больше трех слов (рекомендуется)
• тип переменной (обычно указывается в начале)
• общепринятые сокращения
• символы подчёркивания
• один однобуквенный префикс (рекомендуется)
• один однобуквенный постфикс (рекомендуется)

При написании имён переменных, состоящих из нескольких слов, можно использовать символы подчёркивания для разделения отдельных слов в snake_case стиле. Также для разделения слов можно применять CamelCase стиль. После однобуквенного префикса имя переменной должно начинаться с заглавной буквы.

Примеры:

Правильно Неправильно
 next         
 NeXt       
 iNext        
 Inext      
 next_boot_object  
 nextbootobject 
 iNextObject  
 inextobject
 CNextObject  
 CNEXTOBJECT
 Next         
 Nxt        
 iNext        
 Next_i     
 i_next       
 inext      
 next_i       
 nexti      
 o_next_s     
 o_next_s_p 
 o_next       
 o_s_next   
 oMyNext      
 o_MyNext  /// Плохо смешивать стили в начале 

 

Написание макросов и констант

Константы, макроопределения или элементы перечислений рекомендуется начинать или писать заглавными буквами, а отдельные слова в одном регистре следует разделять символом подчёркивания «_».

const unsigned char MAX_STRING_LENGTH = 32;    /// Максимальная длина строки
#define DEVICE_ID 13                           /// Идентификатор устройства
#define #define  Echo( h, v, ... )             
#define #define  show_all_mc_regs()             

/**
 * Код клавиши
 */
typedef enum
{
    KEY_UP    = 0x48,    /// Вверх 
    KEY_DOWN  = 0x4A,    /// Вниз 
    KEY_RIGHT = 0x4B,    /// Вправо 
    KEY_LEFT  = 0x4C,    /// Влево 
} KeyCode;

Примеры предопределенных макросов

CHAR_BIT
CHAR_MAX
__LINE__
__FILE__
__DATE__
__TIME__
assert,
errno,
math_errhandling,
setjmp,
va_arg,
va_copy,
va_end,
va_start.

Написание имён функций

В именах функций и методов разрешено использовать все три нотации: snake_case + lowerCamelCase + CamelCase. Понятно, что при написании имён функций и методов в верблюжьей нотации каждое слово, входящее в состав имени, следует писать, начиная с заглавной буквы, остальные буквы имени должны быть строчными.

ВНИМАНИЕ ИСКЛЮЧЕНИЕ:
Для всех методов одного модуля можно использовать префикс в виде названия модуля в верхнем регистре (UPPER) и символа подчёркивания (префикс может быть в виде сокращённого имени модуля).

Правильно Неправильно
 void get_cpu();         
 void getcpu();          
 void GetFunctionName(); 
 void getFunctionname(); 
 void getFunctionName(); 
 void getfunctionName(); 
 void StopOnError();     
 void Stop_On_Error();   
// Функции модуля CAN
void CAN_Init();
void CAN_Open();
void CAN_Close();

// Функции модуля EE
void EE_read();
void EE_write();
                  

 

Написание литералов

Шестнадцатеричные константы следует писать заглавными буквами. При этом префикс константы должен быть написан строчной буквой ‘x’.

0xFF1234AB

При указании типа данных для целочисленных констант или констант с плавающей точкой суффиксы i или f, следует писать строчными буквами.

Исключением является тип данных signed long – суффикс L следует писать заглавной буквой (чтобы случайно не перепутать похожие символы 1 и l).

0.5f
1234567890L
1234567890ul
10e10

Написание имен Классов

Имена классов и типов можно начинать с заглавной буквы.

Также для именования классов и объектов существуют специальные префиксы и постфиксы:

C, _c            Class
T, _t            Type
O, o , o_, _o    Object

Примеры:


Dev

CDev 
dev_c 

TDev 
dev_t 

ODev 
oDev
o_dev
dev_o

Использование множественного числа

Если нечто содержит несколько элементов чего-либо, то для именования такого нечто можно использовать множественное число.

Во множественном числе могут употребляться имена таблиц баз данных имена, имена массивов, кортежей, списков и пр.

Примеры:


Devs
Nums

devs
nums

 

Организация программы

При проектировании программы, её необходимо разбивать на модули.

Модуль — функционально законченный фрагмент программы, оформленный в виде двух или нескольких отдельных файлов с похожим или одинаковым названием, но разным расширением. Обычно файл реализации создаётся с расширение: .c на Си, .cc, .cpp на C++, а заголовочный файл с расширение:.h.

Заголовочный файл предоставляет интерфейс взаимодействия с модулем. Файл реализации содержит реализацию представленного интерфейса модуля.

Организация файлов модулей

Данные внутри файла реализации следует упорядочивать следующим образом:

  1. Спецификация модуля
  2. Директивы #include
  3. Определения макросов
  4. Определения типов
  5. Определения глобальных переменных
  6. Описания функций
  7. Импортируемые глобальные переменные и функции
  8. Реализации функций

Данные внутри заголовочного файла следует упорядочивать следующим образом:

  1. Спецификация модуля
  2. Директивы препроцессора для исключения повторного включения h-файла
  3. Директивы #include
  4. Определения макросов
  5. Определения типов
  6. Определения глобальных переменных
  7. Описания функций
  8. Импортируемые глобальные переменные и функции

Сплиттеры

Для организации спецификации файлов используйте сплиттеры (splitters):

Например:

///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/// @include
///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/// Macroses
///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/// @def
///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/// Globals
///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Prototypes
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/// Imports
///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/// Implementation
///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Использование принципа DRY

РВН рекомендует разработчикам использовать принцип DRY.

DRY — это принцип разработки программного обеспечения, который нацелен на снижение дублирования информации различного рода, особенно в системах со множеством абстракций.

Принцип DRY формулируется как: «Каждая часть знания должна иметь единственное, непротиворечивое и авторитетное представление в рамках системы».

Этот принцип настолько важен, что не требует повторения!

Обычно его упоминают акронимом DRY, который впервые появился в небезызвестной книге The Pragmatic Programmer, но сам по себе, концепт был хорошо известен и активно использовался уже довольно давно.

Принцип DRY применяется к схемам баз данных, планам тестирования, сборкам программного обеспечения и документации.

Когда принцип DRY применяется успешно, изменение единственного элемента системы не требует внесения изменений в другие, логически не связанные элементы. Те элементы, которые логически связаны, изменяются предсказуемо и единообразно.

Создание документации из исходных кодов


Система Doxygen

Соглашения по самодокументированию

Спецификация модулей

Каждый файл модуля должен начинаться с заголовка (шапки файла) и заканчиваться футером (footer):

/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
///                      E O F
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Информация в заголовке должна быть единообразно структурирована. В заголовке в виде комментария указывается следующая информация:
- Назначение модуля
- Описание модуля
- Информация о последней ревизии (средствами системы контроля версий)

При формировании шапки модуля следует использовать стиль документирования Doxygen. Директивы препроцессора для исключения повторного включения заголовочного файла должны иметь следующий формат:

#ifndef MODUL_H
#define MODUL_H

// Описания макросов, типов данных, функций и т.д.

#endif

где MODUL — название данного конкретного модуля.

Все константы, переменные и типы данных необходимо описывать с обязательным комментированием. При комментировании следует использовать стиль документирования Doxygen.

uint32_t row_index;    /// Индекс текущей строки
uint32_t column_index; /// Индекс текущей колонки

Спецификация функций

Описания экспортируемых функций модуля должны быть сгруппированы в заголовочном файле. Для компактности (если нужно) имена входных параметров можно опускать.

///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/// Protos
///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void sic_print_string ( char *                       );
void print_string     ( const char *                 );
void print_hex        ( unsigned long, unsigned long );
void print_dec        ( u64 num      , u8 digits     );

void __attribute__((__check_stack__)) print_unsigned_char( const unsigned char ch );

При описании функций следует использовать стиль документирования Doxygen.

/**
 * @brief:  print_hex()
 *          Display a hex in the Console ...
 *
 * @param:  u64 num, u8 bits
 * @return: void
 */
void
__no_mem
__no_stacks
print_hex( u64 num, u8 bits )
{
	u8 digit;

	/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	/// @internal
	/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	if ( !bits )	return;

	if ( bits % 4 ) bits = (bits/4 + 1) * 4;

	do 
	{
		bits -= 4;
		digit = (num >> bits) & 0x0F;

		if ( digit < 10 ) 
		{
			putchar( 0x30 + digit );
		} 
		else 
		{
			putchar( 0x37 + digit );
		}
	} while ( bits );

}	// End - Function	print_hex

Внутренние (локальные/static/private) функции модуля должны находиться в файле реализации и быть оформлены аналогично экспортируемым функциям модуля.

Если функция реализует какой-либо алгоритм или вычислительный метод, рекомендуется в спецификации функции поместить комментарий с описанием функции, например так, как это показано выше или включать ссылку на описание метода.

Тело функции должен заканчивать footer:

}	// End - Function  ["function name"]

Если функция включает локальные переменные, то их должен отделить от тела функции splitter:

	
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/// @internal
/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

splitter тела функции поможет вам также выравнивать код функции по ширине экрана.

Если функция не включает локальные переменные, то заголовок тела функции можно опустить.
Для однострочных функций может быть опущен footer.

Например:

/**
 * @brief:  print_unsigned_char()
 *          Display an unsigned char in the Console ...
 * 
 * @param:  const unsigned char c  
 * @return: void
 * @author: 
 */
void
__no_stacks
print_unsigned_char( const unsigned char c )
{
	putchar( c );
}

Код реализации функции нужно отделять от кода другой/других функций двумя пустыми строками.

Комментарии в коде

Комментарии нужны для оперативного обновления и расширение кода, исправления в нем ошибок, автодокументирования, сокращения времени на разбирательства в коде и понимания его нетривиальных участков.

Комментарии должны носить не упоминающий, а поясняющий характер. Обычно необходимо описывать что делает код и для чего он это делает. То, как реализован алгоритм, описывать не нужно, это должно быть ясно из самого кода. Если так сделать не получается, то, возможно, стоит пересмотреть то, что вы написали.

Для реализации автодокументирования шапки функций (и методов) должны включать описание самих функций и их аргументов. Также шапки функций могут включать информацию о том, кто написал функцию, когда это было сделано, время модификации и др. Такую информацию также логично размещать в шапках файлов исходного кода. Это обеспечит автодокументирование через Doxygen или kernel-doc и генерацию документации в формате HTML.

В теле функции рекомендуется использовать комментарии в стиле С++ — // ... и по возможности минимизировать использование массовых комментариев в стиле /* ... */.

Обычно комментарии кода должны быть похожи на следующие:

/**
 * @brief: get_ship_speed() 
 *         Возвращает текущее значение скорости корабля
 *         Необходима для вычисления координат корабля.
 *
 * @note:  Может переходить в состояние ожидания,
 *         нельзя вызывать при удерживаемой блокировке.
 */

Комментарии внутри функций должны встречаться редко. Их нужно использовать только в специальных ситуациях, таких как документирование дефектов, или для важных замечаний. Важные замечания должны начинаться со строки:

    "@Warning" или "XXX: "  

А информация о дефектах — со строки: «@bug», как в следующем примере:

/**
 * @bug: Считается, что dog == cat.
 *       В будущем это может быть не так
 */

Для автоматической генерации документации используйте Doxygen.

Документировать код можно путем введения комментариев в специальном формате:

/**
 * @brief: find_treasure()
 *         Нахождение сокровищ, помеченных на карте крестом
 *
 * @note:  Вызывается при удерживаемой блокировке pirate_lock.
 */
void find_treasure( int map, pirate_lock * lock )
{
     /* .. */
}

Комментарии лучше писать на русском языке (или на английском). Они должны кратко пояснять смысл и цели выполняемых действий.

Для более подробной информации см. руководство Doxygen и другие разделы стандарта.

Правильно Неправильно
/// Инициализация массива, из 100 чисел Фибоначчи
uint8_t i = 0;
uint64_t m[ 100 ];
m[ 0 ] = 1;
m[ 1 ] = 1;

/// Каждое следующее = сумме 2х предыдущих
for ( i = 2; i < 100; i++ )
{
	m[ i ] = m[ i - 2] + m[ i – 1 ];
}
// Целочисленный массив из 100 чисел
uint8_t i = 0;
uint64_t m[ 100 ];

// Нулевой = 1
m[ 0 ] = 1;

// Первый = 1
m[ 1 ] = 1;

// Цикл по i от 2 до 100
for ( i = 2; i < 100; i++ )
{
	m[ i ] = m[ i - 2] + m[ i – 1 ];
}

 

При документировании отдельных фрагментов кода рекомендуется использовать однострочные комментарии (отделённые символами "//").

Правильно Неправильно
/// Вычисляем объём тела
volume = width * height * length;
/// Вычисляем объём тела
volume = width * height * length;

 

Комментарии следует располагать непосредственно перед описываемым участком кода. Однотипные короткие конструкции допустимо комментировать, располагая описания справа от инструкций. Такие комментарии следует выравнивать по одному столбцу.

Правильно Неправильно
/// Инициализация начальными значениями
m[ 0 ] = 7; // Первый этап (5-10 шагов)
m[ 1 ] = 9; // Второй этап (8-12 шагов)
m[ 2 ] = 4; // Третий этап (1-5 шагов)
m[ 3 ] = 5; // Четвёртый этап
            // (3-6 шагов)
// Первый этап (5-10 шагов)
m[ 0 ] = 7; //  
m[ 1 ] = 9; // Второй этап (8-12 шагов)
m[ 2 ] = 4; // Третий этап (1-5 шагов)
            // Четвёртый этап (3-6 шагов)
m[ 3 ] = 5;

 

В случае длинных блоков рекомендуется после закрывающей скобки блока в комментарии написать оператор блока.

if ( ready )
{
    // большой блок кода

}	// if

for ( i = 0; i < 10; i++ )
{
    // большой блок кода

} 	// for i

При документировании кода необходимо отделять текст комментария от символов комментария ("//") одним пробелом.

// Текст комментария

Для комментариев следует использовать такой же отступ, как и в соответствующем ему коде.

// Цикл по строкам таблицы
for ( i = 0; i < 10; i++ )
{
    // Цикл по столбцам таблицы
    for ( j = 0; j < 10; j++ )
    {
        // Суммируем элементы таблицы
        sum += m[ i ][ j ];
    }
}

Форматирование исходного кода

Объявления

Каждое объявление необходимо размещать на отдельной строке. Счётчики циклов желательно объявлять самыми последними.

Правильно Неправильно
Color   current_color;
Color   next_color;
uint8_t row_index;
uint8_t column_index;
uint8_t i;
Color   current_color, next_color;
uint8_t row_index, column_index, i;

 

При таком размещении проще дописывать комментарии к каждому объявлению, проще искать и редактировать переменные.

При объявлении переменных их следует группировать по логической взаимосвязи.

Правильно Неправильно
Color   current_color;
Color   next_color;
uint8_t row_index;
uint8_t column_index;
uint8_t i;

Color current_color;
uint8_t column_index;
Color next_color;
uint8_t row_index;
uint8_t i;

 

Отступы и выравнивания

Инструкции, находящиеся под управлением блока, должны размещаться со сдвигом. Отступы будут подчеркивать логическую структуру программы. Благодаря этому будут ясно видны инструкции, расположенные внутри блока.

С-компилятор не обращает внимания форматирование кода, но наличие в нужных местах отступов и пробелов существенно влияют на то, насколько легко код будет восприниматься при его просмотре.

В РВН для выравнивания текста и введения отступов используются символы табуляции.

Размер одного символа табуляции при отображении соответствует 8 позициям.

Это не означает, что для структурирования нельзя использовать 8
или 4 символа пробела либо что-нибудь еще.

Это означает, что каждый уровень отступа равен одному символу табуляции от предыдущего, и что при отображении длина символа табуляции равна 8 символам.

По непонятным причинам это правило почти всегда нарушается, несмотря на то, что оно очень сильно влияет на читабельность. Восьмисимвольная табуляция позволяет очень легко визуально различать отдельные блоки кода даже после нескольких часов работы.

Если табуляция в восемь символов кажется очень большой, то не нужно делать так много вложений кода. Почему ваши функции имеют пять уровней вложенности? Необходимо исправлять код, а не отступы.

Альтернатива: В качестве отступа для сдвига блока можно использовать 4 (четыре) символа пробела.

Отступы и выравнивания должны отражать структурную вложенность языковых конструкций.

Правильно Неправильно
for ( i = 0; i < 10; i++ )
{
	for ( j = 0; j < 10; j++ )
	{
		Sum += m[ i ][ j ];
	}
}
for ( i = 0; i < 10; i++ ) 
{
for ( j = 0; j < 10; j++ )
{
	Sum += M[ i ][ j ];
}
}

for ( i = 0; i < 10; i++ ) {
for ( j = 0; j < 10; j++ )
{
	Sum += M[ i ][ j ];
}}
for ( i = 0; i < 10; i++ )
for ( j = 0; j < 10; j++ )
{
    Sum += m[ i ][ j ];
}
for ( i = 0; i < 10; i++ ) 
for ( j = 0; j < 10; j++ ) {
	Sum += M[ i ][ j ];
                              }

 

Рекомендуется: при переносе части параметров на другую строку, при объявлении или вызове функций вторая и последующие строки должны быть выровнены по первому параметру.

static void get_pirate_parrot( const char * 	name            ,
                               unsigned long	disposition     ,
                               unsigned long	feather_quality );

Можно разбить длинную строку на части, но не располагать параметры функций друг под другом, а просто использовать два символа табуляции для отделения продолжения длинной строки от ее начала, как показано ниже:

int find_pirate_flag_by_color( const char * color,
                const char *name, int len );

Поскольку на этот счет нет определенного правила, выбор остается за разработчиком.

Описание переменных следует оформлять, выравнивая в вертикальные столбцы: типы, идентификаторы и начальные значения.

unsigned long  message_count     = 0            ;
float          correction_factor = 0.0f         ;
ID_MESSAGE     message           = MESSAGE_NONE ;
KEY_CODE       key_code          = KEY_NONE     ;

Чтобы лучше была видна логическая структура выражения, мы рекомендуем писать только по одной инструкции на каждой строке и обрамлять пробелами знаки операций. Это не распространяется на случай когда вы хотите выделить логическую структуру путем табличной организации текста. Например:

if      ( w1max <  weight ) { w2max = w1max;   w1max = weight; }
else if ( w2max <  weight ) { w2max = weight;  w1max = 0;      } 
else if ( w1max == weight ) { w2max = w1max;                   }
else                        { ASSERT( w1max0,  "BUG" , EIO );  }

Фигурные скобки

В РВН принято два соглашения по размещению фигурных скобок. Мы рекомендуем первое соглашение, но вы можете выбрать любое из них или оба сразу.

Первое и рекомендуемое соглашение - размещать открывающую фигурную скобку во второй строке сразу за соответствующим оператором. Закрывающая скобка помещается в отдельной строке, как в следующем примере:

if ( fox ) 
{
	dog();
	cat();
}

Как видим, по стандарту РВН фигурные скобки размещаются непосредственно под ключевым словом и по горизонтали на одном уровне с ним.

В случае, когда за закрывающей скобкой продолжается то же самое выражение, то продолжение выражения записывается с новой строки, как показано ниже:

if ( fox ) 
{
    ant();
    pig();
} 
else
{
	dog();
	cat();
}

while  ( 1 )
{
    dog();
    cat();
}

Для do можно писать следующим образом:

do
{
    dog();
    cat();
} while  ( fox );

Второе соглашение - размещать открывающую фигурную скобку в первой строке, сразу за соответствующим оператором. Закрывающая скобка помещается в первой позиции с новой строки, как в следующем примере:

if (fox) {
    dog();

    cat();
}

В случае, когда за закрывающей скобкой продолжается то же самое выражение, то продолжение выражения записывается в той же строке, что и закрывающая скобка, как показано ниже:

if (fox) {
    ant();

    pig();
} else {
    dog();

    cat();
}

или следующим образом.

do {
    dog();

    cat();
} while (fox);

Для функций это правило не действует и функции нужно оформлять только так, как показано ниже:

/**
 * foo()
 * 
 * Обеспечивает ...
 * 
 * @param:  void 
 * @return: err - unsigned long 
 * @author: Author 
 */ 
unsigned long foo( void ) 
{ 
        unsigned long err; 
         
        ///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        /// @internal 
        ///~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ... 
         
        return err; 

 }      // End - Function 
 

Для выражений, которые помещаются в одну строчку фигурные скобки можно опускать.

if ( foo ) bar(); 

while ( i < j )
    i = 2 * j;

Хотя синтаксически для однострочных операций фигурные скобки не требуются, но, несмотря на это, их использование крайне рекомендовано.

Фигурные скобки делают код более целостным и понижают число ошибок при дальнейшем расширении.

Примеры расстановки фигурных скобок

/// Простое ветвление:
if ( key_code == KEY_ESC )
{
    ClearScreen();
}

/// Сложное ветвление:
if ( key_code == KEY_ESC )
{
    ClearScreen();
}
else
{
    PrintString( "Для очистки экрана нажмите клавишу 'Esc'" );
}

/// Множественное ветвление ( конструкция else if ):
if ( key_code == KEY_ESC )
{
    return;
}
else if ( key_code == KEY_ENTER )
{
    ClearScreen();
}
else
{
    PrintString( "Нажмите клавишу 'Esc' или 'Enter'" );
}

/// Множественный выбор (еще одна реализация вышеприведённого примера):
switch ( key_code )
{
    case KEY_ESC:

		return;

    case KEY_ENTER:
        ClearScreen();

        break;
    default:
        PrintString( "Нажмите клавишу 'Esc' или 'Enter'" );
}

/// Множественный выбор (сложный случай): 
switch ( msg )	/// Обрабатываем входящее сообщение
{
    // Инициализация диалога
    case WM_INITDIALOG:
        Brush = CreateSolidBrush( RGB( 255, 127, 127 ) );

        break;
    // Команда
    case WM_COMMAND:
        switch ( LOWORD( wParam ) )
        {
            // Отмена / кнопка Выход
            case IDCANCEL:
                EndDialog( window, IDCANCEL );
				
                break;
            // Все остальные команды
            default:
                return false;
        }

        break;

    // Все остальные типы сообщений
    default:
        return false;
}

/// Цикл while:
while  ( условие )
{
    операторы;
}

/// Цикл do while:
do
{
	операторы;
} while  ( условие );

/// Цикл for:
for ( i = 0; i < 10; i++ )
{
    операторы;
}

Пробелы

Операторы +, *, /, = и т.п. нужно отделять от операндов одним пробелом.

Логический оператор отрицания ! следует писать слитно с операндом.

Правильно Неправильно
sum = a + b;
result = !result;
sum=a+b-c;

 

После запятой или точки с запятой, если она не последняя в строке, должен быть пробел.

Правильно Неправильно
for ( y = 0; y < 10; y++ )
{
	PrintStringXY( 1, y, "Привет!" );
}
for ( y = 0;y < 10;y++ )
{
	PrintStringXY( 1 , y , "Привет!" );
}

 

После открывающей круглой скобки и перед закрывающей круглой скобкой рекомендуется ставить пробел

Правильно Неправильно
PrintStringXY( 1, 1, "Привет, мир!" );
PrintStringXY(1, 1, "Привет, мир!");

 

При работе с массивами после открывающей квадратной скобки и перед закрывающей квадратной скобкой рекомендуется ставить пробел.

Правильно Неправильно
 Matrix[ row_index ][ column_index ];
 Matrix[row_index][column_index];

 

Для наглядности можно использовать два и более пробелов подряд.

Правильно Можно и так
PrintString( "Привет, мир!" );
PrintString     ( "Привет, мир!"      ) ;

 

Для функций рекомендуется не ставить пробел до открывающей круглой скобки, а для управляющих конструкций, таких как if, for, while (и им подобных) до открывающей круглой скобки пробел ставить можно.

for ( y = 0; y < 10; y++ )
{
	if ( y == 5 )
	{
		my_func( 5 );
		myPrintString( "Привет!" );
	}
}

Длина строк программного кода

При написании кода необходимо стараться, насколько это возможно, чтобы длина строки была не больше 80 символов.

Это позволяет строкам при отображении на терминале размером 80x24 символа вмещаться в одну строку терминала (не превышать ширины экрана 80 символов).

Если это требование не удается выполнить, то нужно стараться, чтобы длина строки помещалась в ширину окна текстового редактора без появления символов продолжения строки.

При необходимости некоторые инструкции можно перенести на другую строку. По возможности нужно стараться избегать переноса на новую строку только одного операнда.

Внимание: не существует стандартного правила, что делать в случае, если длина строки кода обязательно должна быть больше 80 символов.

Некоторые разработчики просто пишут длинные строки, возлагая ответственность за удобочитаемое отображение строк на программу текстового редактора.

Другие разработчики разбивают такие строки на части и вручную вставляют символы конца строки в тех местах, которые кажутся им наиболее подходящими для этого и отделяют продолжения разбитой строки от ее начала двумя символами табуляции и пр.

Размер кода функций

Существует мнемоническое правило: функции не должны иметь больше десяти локальных переменных и по объему кода превышать одного-двух экранов текста. А еще лучше, если вы будете создавать функции не длиннее 40 строк. При большом количестве строк необходимо вынести часть логики в отдельные функции.

Каждая функция должна выполнять одно действие, но делать это хорошо. Не вредно разбить функцию на ряд более мелких функций. Если возникает беспокойство по поводу накладных расходов за счет вызова функций, то можно использовать подстановку тела — inline.

Исправление ранее написанного кода

Если в ваши руки попал код, который даже близко не соответствует стилю написания кода проекта, то все равно не стоит терять надежды. Немного упорства, и утилита indent поможет сделать все как надо.

indent — отличная утилита GNU, которая предназначена для форматирования исходного кода в соответствии с заданными правилами.

Установки по умолчанию соответствуют стилю форматирования GNU, который выглядит не очень красиво. Для того чтобы утилита выполняла форматирование в соответствии со стилем написания например кода ядра Linux, необходимо использовать следующие параметры.

indent -kr -i8 -ts8 -sob -180 -ss -bs -psl [файл]

Можно также использовать сценарий scripts/Lindent, который вызывает утилиту indent с необходимыми параметрами.

Методологии и технологии

Переносимость

porting.jpg

Переносимость — это свойство ПО, обеспечивающее перенос (портирование) выполнения кода с одной аппаратной платформе, для выполнения на другой.

Для пользовательских программ переносимость не всегда является целью, но для ядер OC и загрузчиков она часто остается таковой. Это значит, что их мультипортируемый код должен правильно выполняться на значительном количестве аппаратных платформ.

Разработка переносимого кода

Портирование требует строгого учета множества факторов, а именно:

• тип платформы (64, 32, 16, 8 бит)
• размер машинного слова
• использование скрытых и специальных типов данных
• размеры типов данных
• знак char
• выравнивание в памяти (выравнивание нестандартных типов, структур и пр.)
• порядок следования байтов
• получение и использование частоты работы ЦП
• получение и использование частоты срабатывания системного таймера
• размер страницы памяти
• аппаратная зависимость механизмов синхронизации
• порядок выполнения операций ЦП (преемптивность, верхняя память, SMP)
• аппаратная зависимость для некоторых обработчиков прерываний
• знание поведения компилятора и обход реализационно-зависимого поведения
• отказ/принятие во внимание свойств C, зависящих от реализации
• использование длинных имён с внешней связью
• использование ассемблера и ассемблерных вставок
• аппаратная зависимость части кода инициализация памяти и некоторых регистров
• и т.д

Всегда помните о проблемах переносимости и стремитесь к созданию ясного и портируемого кода. В большинстве случаев нужно просто гарантировать, что типы данных используются правильно.

Выбор языка программирования C — первый шаг в сторону уменьшения затрат на переносимость. Но есть ещё много других вещей, которые придется учитывать.

Отметим, что низкоуровневый код и код, который должен выполняться очень быстро, следует разрабатывать аппаратно зависимым и обычно на языке ассемблера.

В целом разработка переносимого кода должна подразумевать следующее:
• Код нужно создавать с учетом самого общего сценария
• Нужно предполагать, что случиться может все
• Нужно принять меры на все, что может случиться
• Нельзя полагаться на то, что будут доступны все возможности
• Нужно опираться только на минимум, доступный всем аппаратным платформам
• Нужно всегда использовать только переносимые типы в интерфейсах

При создании переносимого кода изолируйте аппаратно-зависимый и системно-зависимый код в отдельных модулях. Дозировано используйте препроцессор для облегчения переносимости. Минимизируйте аппаратно-зависимый объем кода.

МОБИЛЬНОСТЬ ПРОГРАММ НА ЯЗЫКЕ СИ

Мобильность программ — это свойство, позволяющее выполнять программы на разных ЦП, работающих под управлением разных версий ОС UNIX, с минимальными изменениями.

Изложенные в этом разделе рекомендации не являются строгими правилами. Не существует методики, гарантирующей автоматическое получение мобильной программы. Если вы будете использовать эта рекомендации при разработке своих программ, то ваши программы будут более мобильны, а также лучше организованы, более легки для понимания, изменения и поддержания.

Верификатор lint

Верификатор (программа семантического контроля) lint обеспечивает строгую проверку типов и выявляет многие конструкции, ухудшающие мобильность программ, написанных на языке Си. Если использовать верификатор lint на всех этапах разработки, то программный продукт будет гораздолегче переносить на любую версию ОС UNIX. Если вам потребуется переписать старую программу для повышения мобильности, то верификатор lint поможет вам выявить все сомнительные места.

Верификатор lint - это хорошее сервисное средство для разработки мобильных программ. Однако не надейтесь, что ваша программа является мобильной, если верификатор lint "не имеет к ней никаких претензий", ине полагайтесь на него, если программа написана плохо, так как верификатор может пропустить некоторые немобильные конструкции. Следуйте изложенным в этом разделе рекомендациям, улучшающим стиль программ.

Зависимость от компилятора

Некоторые детали в языке Си не стандартизированы. Это может проявиться в небольших различиях при обработке программы разными компиляторами. Какими бы "малыми" эти различия не были, они могут породить серьезные проблемы при переносе программ с одной вычислительной системы на другую. Например, в описании языка Си не определен порядок вычисления операндов большинства бинарных операций, таких, как сложение и умножение. Следовательно,не определен порядок появления возможных побочных эффектов. Поэтомуне делайте никаких предположений о реализации свойств языка, которые строго не определены.

Зависимость от аппаратуры

Не полагайтесь на определенный размер машинного слова.

Размер данных типа int зависит от размера машинного слова, различающегося у разных ЦП. Если вы не уверены в результате операций над целыми числами, используйте тип long, чтобы избежать проблемы переполнения.

Не гарантируется, что размер данных типа int совпадает с размером машинного слова. В языке Си определяется только, что размер данных типа short меньше или равен размеру данных типа int, который, в свою очередь, меньше или равен размеру данных типа long. Размер слова может сказаться на обработке двоичных масок.

П р и м е р

#define MASK 0177770 /* неправильно*/ int х;

х &= MASK;

В этом примере три правых бита целого х будут обнуляться только в том случае, если данные типа int занимают 16 бит. Но если размер данных типа int больше 16 бит, то кроме этого будут обнулятьсялевые биты данного х. Чтобы избежать таких проблем, используйте следующее макроопределение:

#define MASK (~07) /* правильно */

int х;

х &= MASK;

Этот пример корректен для всех ЦП независимо от размера данных типа int.

Тщательно проверяйте операции сдвига

Максимальное число бит, которые могут быть сдвинуты вправо или влево, различно на разных ЦП. Если заданный в операции сдвиг превысит допустимый максимум, то результаты операции будут непредсказуемы.

Перед сдвигом преобразуйте целые значения к типу unsigned. На некоторых ЦП сдвиг выполняется логически, т. е. освобождающиеся разряды обнуляются. На других сдвиг производится арифметически, и освобождающиеся разряды заполняются значением знакового разряда. Однако в языке Си гарантируется, что значения типа unsigned сдвигаютсялогически.

Используйте поименованные константы

Использование в программе числовых констант, особенно когда смысл их неочевиден, является плохим стилем программирования. Числовые константы лучше определять в программе символическими именами, связанными с числовыми константами командой препроцессора #define. Такие определения легко находить и модифицировать, если ониразмещены в некоторомстандартном месте. Обычно это начало программы или файл заголовка.

П р и м е р

#define SCREENWIDTH 80

Такое определение позволяет использовать поименованную константу SCREENWIDTH вместо числа 80.

Определяйте размер объекта операцией sizeof

Для определения размера некоторого объекта часто используют константы, что снижает мобильность программ. Использование операции sizeof позволяет решить эту проблему.

П р и м е р

#define NUMELEM(ARRAY)\ (sizeof(ARRAY) / sizeof(*(ARRAY)))

Такое макроопределение обеспечивает мобильный способ определения числа элементов в массиве ARRAY.

Не используйте несколько символов в одной символьной константе

Поскольку символьные константы представляются значениями типа int, определение языка Си позволяет в принципе задать символьную константу, состоящую из нескольких символов. Однако порядок размещения символов в машинном слове различен на разных ЦП.

Не полагайтесь на внутреннюю кодировку целых чисел

Большинство ЦП представляет целые числа в дополнительном коде, но некоторые - вобратном коде. Поэтому не используйте возможности, которые предоставляет дополнительный код. Например, сдвиг на 1 бит влево отрицательного числа (чтобы уменьшить его значение в два раза) не приведет к желаемому результату на ЦП с обратным двоичным кодом.

Формат чисел с плавающей точкой различен на разных ЦП

Представление чисел с плавающей точкой на разных ЦП различно. Поэтому точность результатов арифметических вычислений с плавающей точкой может быть разной на различных ЦП. Избегайте или в крайнем случае подробнодокументируйте все вычисления, зависящие от точности.

Не полагайтесь на определенный порядок и число байт в слове

Число байт и порядок их размещения а машинном слове различны у разных ЦП.

П р и м е р

Следующая функция определена неправильно - на выход будет записан нулевой символ, есликакой-тобайт в слове имеет меньший адрес, чем младший байт;

#define STDOUT 1 
putchar(c); /* неправильно */
int с;
{
write(STDOUT, (char *) &c, 1);
}

В данном примере аргумент с должен описываться как имеющий тип char; в этом случае преобразование типа данных станет ненужным.

Не полагайтесь на определенное число бит в байте

Поскольку число бит в байте у разных ЦП различно, то не предполагайте, что байт всегда занимает 8 бит. Чтобы определить число бит в байте, используйте поименованную константу, содержащуюся в стандартном файле:

/usr/include/values.h

З а м е ч а н и е. Все системные файлы-заголовкиразмещаются в каталоге /usr/include.

Будьте осторожны с символами, имеющими знак

На некоторых ЦП символы представляются как целые значения со знаком, и при вычислении выражений данные типа char обрабатываются с учетом знака. Для повышения мобильности можно использовать явное описание типа unsigned char или преобразовывать символы перед обработкой к типу unsigned char. В других случаях надо использовать данные целого типа.

П р и м е р

Если на данной ЦП допустимы символы со знаком, то существует опасность, что индексация символом некоторого массива приведет к выходу за его границы:

#define TABSIZE 256 char с;

extern char table [TABSIZE];

с = table [c]; /* неправильно */

Чтобы избежать этого, опишите переменную с как имеющую тип unsigned char или индексируйте таблицу значением, преобразованным к типу unsigned char.

П р и м е р

Следующий фрагмент программы ошибочен - конец файла никогда не будет обнаружен, если символы представляются как беззнаковые значения:

#include 

/* неправильно */
char с;
if ((с = getchar()) != EOF)

Если значение символа не может быть отрицательным, то переменная с никогда не станет равной поименованной константе EOF, которая равна-1.Библиотечная функция getchar возвращает значение типа int, поэтому с надо описать как переменную типа int.

Не комбинируйте разные поля бит

Не используйте поля бит для представления данных на внешних носителях

Поля бит можно сделать мобильными, если не объединять разные поля. Максимальный размер поля бит зависит от размера машинного слова, и поля бит не могут пересекать границу слова. Кроме того, порядок размещения полей в слове (слева направо или справа налево) зависит от типа ЦП.

Использование полей бит для описания размещения данных на внешних носителях делает программу немобильной. Для того чтобы упростить эту проблему, поместите определения полей бит в файл заголовка и укажите, что они зависят от типа ЦП.

Используйте операцию преобразования типа для указателей

В общем случае операции преобразования типа указателя не являются мобильными. Однако можно преобразовать указатель в данное любого целого типа, имеющее достаточно большой размер, и при обратном преобразовании получить исходное значение указателя. Аналогично указатель на некоторый объект может быть преобразован в указатель на меньший объект и обратно.

Учитывайте выравнивание при изменении значения указателя

Если вы преобразуете указатели из одного типа в другой, то при выполнении программы может возникнуть ошибка адресации вследствие ограничений на выравнивание данных в машинной памяти Используйте библиотечную функцию malloc, воэвращающую указатель на символ, выравненный в памяти в соответствии с требованиями данной ЦП, так что этот указатель может быть преобразован в указатель любого типа.

Следите за сравнением указателей, имеющих знак

Некоторые ЦП выполняют сравнение указателей с учетом знака, другие делают беззнаковое сравнение. Это различие несущественно, если сравнивать указатели, содержащие правильные адреса. Если указателю будет присвоено значение -1,то в зависимости от ЦП оно бупет рассматриваться или как наибольшее допустимое значение, или как недопустимое значение (меньше минимально допустимого).

Единственная константа, которую можно "безопасно" присваивать указателю, - это нуль, преобразованный к типу соответствующего указателя.

Следите за переполнением значения указателей

Арифметические преобразования указателей могут привести к переполнению или потере значимости. Такие циклические преобразования значений (от наибольшего к наименьшему или наоборот) могут возникнуть при адресации массива, расположенного в начале или в конце машинной памяти

П р и м е р

Этот фрагмент программы показывает возможность появления потери значимости:

struct
large x[SIZE], *p;

/* неправильно */
for (p=x[SIZE - l]; p >=x; p--)

Если массив х расположен в начале памяти, то возможна ситуация, при которой х - 1 будет не меньше, а больше х вследствие перехода через нижнюю границу диапазона значений указателей (потери значимости).

Не полагайтесь на конкретную кодировку символов

Не используйте в программе предположения, что символы в кодовом наборе располагаются последовательно.

П р и м е р

char с;

if (с >= 'а' && с <= 'z' ) /* неправильно */

Такая проверка символа с на принадлежность к строчным буквам не является мобильной. Чтобы такая проверка правильно выполнялась на других ЦП, сделайте так:

char с;

if (islower(c)) /* правильно */

Библиотечная функция islower определена в библиотеке стандартных функцийввода-выводаи являетсямашинно-зависимойПоскольку ее спецификация мобильна, то данная функция обеспечивает мобильную проверку символов.

Учтите, что разные символьные коды могут отличаться по числу входящих в них символов. Не используйте разность значений двух букв для вычисления лексикографического расстояния между ними.

Не используйте программные трюки, зависящие от аппаратуры

Любое повышение эффективности выполнения программы, достигаемое за счет знания особенностей конкретной ЦП, обычно не оправдывает связанную с этим потерю мобильности.

Хорошо организованные программы

Программа называется хорошо организованной, если ее легко читать, модифицировать,

эксплуатировать и, следовательно,переносить на другие ЦП.

Все определения, связанные с конкретной операционной средой и конкретной ЦП, помещайте в файл заголовка.

Важнейшим средством разработки мобильных программ являются команды препроцессора #include и#define. Помещайте все определения типов данных, поименованных констант, макроопределения, используемые более чем одной программой, в единый файл заголовка так, чтобы все возможные изменения были локализованы.

П р и м е р

#include 

С помощью этой команды в программу включается стандартный файл заголовка /usr/include/values.h, который содержит аппаратные константы.

Используйте файлы заголовка для общих определений одного проекта, т. е. множества связанных программ. Используйте локальные файлы заголовка для отдельных программ.

Используйте файл заголовка для локализации данных, зависящих от операционной среды, таких как имена файлов и режимы выполнения. Все, что может измениться при переходе на другую операционную систему или в рамках той же системы, помещайте в файлы заголовка, где эти данные легко могут быть модифицированы.

Не помещайте в файлы заголовка определения внешних переменных, которые управляют распределением памяти. Используйте файлы заголовкатолько для определения команд препроцессора и типов данных.

Для локализации программных фрагментов, зависящих от ЦП, используйте функции, условную компиляцию и команду #define.

Функции, зависящие от конкретной ЦП, объедините в отдельный исходный файл. Если таких файлов несколько, то соберите их в отдельном каталоге.

Фрагменты исходного кода, зависящие от аппаратуры, заключайте в команды условной компиляции

П р и м е р

Следующий фрагмент программы описывает стек, который может наращиваться в разных направлениях в зависимости от аппаратных особенностей ЦП.

int *stackptr; #ifdef MACHINE

*--stackptr= datum; /* растет вниз */

#else

*++stackptr = datum; /* растет вверх */

#endif

Для локализации характеристик конкретной ЦП можно использовать макроопределения

П р и м е р

#define BITSPERBYTE 8 #define BITS(TYPE)\ (sizeof(TYPE) * BITSPERBYTE)

Спецификация поименованной константы BITSPERBYTE мобильна, реализация -не мобильна. В макроопределении BITS мобильна как спецификация, так и реализация11.

Проверяйте число и тип аргументов, передаваемых функциям

Спецификацией здесь называется определяемая лексема, а реализацией - определяющее константное выражение.

Убедитесь, что число и тип аргументов, передаваемых функциям при вызове, согласуются с числом и типом формальных параметров этих функций. Даже если при конкретном вьвове можно передавать меньше аргументов, чем определено, не опускайте ни одного из них; опишите пустые фактические аргументы, такие как нулевые значения.

В файле /usr/mclude/varargs.h описаны средства для мобильного определения функций с переменным числом аргументов. Например, библиотечная функция printf реализована с использованием этих средств.

Используйте стандартные библиотечные функции; не определяйте собственные системные вызовы, если без этого можно обойтись.

Стандартные библиотечные функции ОС обеспечивают большой выбор универсальных процедур. Библиотеки ОС содержат стандартные функции, обеспечивающие доступ к таким средствам операционной системы, как ввод и вывод. Библиотечные функции обеспечивают повышение мобильности, изолируют вашу программу от возможных изменений в операционной системе.

Тщательно определяйте внешние имена

Для облегчения эксплуатации и увеличения мобильности программы определяйте все внешние переменные в отдельных исходных файлах. Не забудьте, что все остальные исходные файлы программы должны ссылаться на эти определения с помощью описаний extern. При этом можно использовать разные методы. Можно поместить эти внешниеописания в начало исходных файлов программы (с помощью включения файлов) илиописать эти внешние переменныев функциях, которые их используют.

Максимальное число значимых символов в идентификаторах внешних переменных и функций зависит от операционной системы Кроме того, некоторые операционные системы преобразуют все строчные буквы в прописные. Компоновщик (редактор связей) сообщает о конфликтах имен, но обнаруживает не все возможные ошибки, поэтому не возлагайте на эту программу обязанность разрешать противоречия в именах.

Используйте описание typedef для локализации определения типов данных, зависящих от ЦП

Описание typedef обеспечивает локальные определения типов тех данных, которые зависят от конкретной ЦП. Если вы измените определение типа, заданное описанием typedef, то соответственно изменятся все переменные, описанные с помощью этого производного типа. Система обеспечивает набор стандартных определений в файле

/usr/include/sys/types.h

П р и м е р

typedef unsigned short ino_t; /* индекс файла */

Этот пример показывает типичное использование определения типа в файле

/usr/include/sys/types.h

Мобильность файлов данных

Для переноса файлов, содержащих двоичные данные, используйте символьный ввод-вывод.

Файлы двоичных данных по сути своей не мобильны, поскольку разные ЦП используютразное внутреннее представление данных. К сожалению, не существует простого пути для переноса файлов данных. Порядок байт в слове может привести к серьезным проблемам при переносе данных с одной ЦП на другую по принципу "байт в байт" Кроме того, коды символов могут быть разными на разных ЦП.

Один из способов решения этой проблемы заключается в раз работке специальных программ преобразования для конкретных форматов данных. Другой подход заключается в записи байт, составляющих объект данных, в некотором машинно-независимомпорядке Для передачи символьных данных используйте библиотечные функции printf и scanf, хотя это и непрактично.

Ссылки

Опыт и нюансы реализации переносимого кода детально освещены в следующих статьях:
Р.Лав Разработка ядра Linux
Переносимость. Основы
Написание переносимых программ
Переносимость ПО GNU

Внедрение принципа DRY или не повторяйся

Иногда существующий проект включает много повторяющегося кода: некоторые функции реализованы неоднократно (возможно, разными разработчиками) и пр.

При этом вносить изменения в WET-код («Write Everything Twice») тяжелее, чем в DRY, ибо приходится держать в голове много разных мест (участков кода) и взаимозависимостей между ними. При модификации кода, который вызывает ту или иную функцию, бывает сразу трудно понять, какая же из существующих имплементаций используется (зависит от #define-ов и от #include-ов).

В противоположность этому, при успешном применении принципа DRY правка любого участка кода не требует внесения изменений в других местах. То есть код модифицируется только в одном месте и изменяется предсказуемо и единообразно.

Вывод: нужно взять курс на исключение дублирующегося кода, чистку и рефакторинг всех исходных файлов проекта.

Внедрение модульности

Иногда бывает, что в проекте код различных сущностей перемешан в больших общих файлах. Такой перемешанный код:

• небезопасен и незащищен от случайных изменений
• нечитабелен и, как следствие, плохо поддается модернизации

При поиске ошибки или расширении кода нужно найти соответствующие точки входа. Наличие IDE часто не помогает - бывает еще не ясно, что и где нужно искать. При этом приходится долго перемещаться по экрану среди бесчисленных ifdef (к слову, в ядре Linux использование директив ifdef категорически не рекомендуется). Все вышеперечисленное затрудняет понимание кода и тормозит его обновление.

Что нужно сделать:
Программу необходимо разбивать на модули (см. раздел организация проекта).

Преимущества модульности

Модульность позволит изолировать независимые части проекта друг от друга. Код проекта станет меньше (ничего лишнего) и яснее (унификация), а следовательно, его будет легче наращивать и поддерживать. Все вместе позволит вам ускоренно и безопасно развивать проект, а именно:

• быстро внедрять новые сущности
• исправлять ошибки и развивать отдельные части проекта без негатива для других
• упростить обновления (вплоть до случая, когда для исключения или модификации модуля надо лишь изменить одну-две строчки кода в определенном месте)

Модульность- это прежде всего системность, совокупность взаимодействующих объектов.

Из-за её отсутствия многие интересные решения иногда не находят должной поддержки и, как следствие, перспективное развитие проекта значительно сдерживается. Модульность позволит отказаться от практики все, что угодно, но только не правки работающего кода.

Настоящую модульность можно легко обеспечить, если использовать ООП или псевдо ООП-подход (там, где это уместно).

Псевдо ООП подход – это механизм создания классов на основе структур языка С, которые объединяют указатели на функции и данные.

Объектно-ориентированный подход

В ANSI-C обычно все проблемы решаются в чисто процедурном стиле. Процедурный стиль - это разрозненные функции, глобальные переменные, #ifdef, обертки и пр.

Почему нужен объектно-ориентированный подход (далее просто ООП):

1. Для получения истинной модульности через инкапсуляцию. Все собрано в одном месте – в объекте. На объект легко ссылаться, копировать и управлять его данными.

2. Для повышения безопасности (защита от случайных изменений, типизация, отсутствие глобальных переменных).

3. Для настоящей расширяемости и поддержки принципа DRY (через наследование, полиморфизм, перегрузку и замещение методов и пр.).

4. Для увеличения производительности разработки. Класс можно существенно расширить или изменить, не затрагивая при этом основного кода. Плюс механизм управления доступом позволит компилятору заблаговременно находить ошибки.

В результате ООП сделает код проекта безопасней и проще, причем почти без снижения общей производительности. ООП обеспечит возможность создавать единые сущности (объекты софта и аппаратуры) и избавиться от разрозненных функций и глобальных переменных. Объекты будут включать нужные свойства и методы, необходимые для использования и наращивания нового функционала в истинно модульном стиле. Сode-Reuse и DRY упростят обновления и расширяемость кода (наследование, полиморфизм, замещение) и, следовательно, станет не нужно править все и везде, а лишь изменить часть кода.

Что надо сделать: использовать объектно-ориентированный подход (псевдо-классы С), но только там, где это действительно полезно и упрощает код. Если нужно, выполнить рефакторинг уже существующего кода там, где это уместно.

Поддержка исключений в ANSI-C

Почему нужно: в сложных системах (написанных на других языках программирования: С++, С#, Delphi, Java, PHP и пр.) для реакции на ошибки применяется механизм обработки исключений. При этом код становится проще для понимания и пригодней для возможных будущих доработок.

Что надо сделать в ANSI-C:

• реализовать удобные для использования макросы подсистемы try...catch...finally (конечно, с учётом ограничений языка С)
• с их помощью переписать участи кода, где нужна и/или производится обработка ошибок

Дополнительный бонус: код будет выполняться быстрее (т.к. throw – это обычный goto), и он не требует нетривиальных пост-проверок в точках, куда выходят break.

Используйте то, что уже есть

Не нужно изобретать велосипед. Обычно большой проект или среда, в которой вы работаете, предоставляет множество возможностей. Например функции работы со строками, функции вывода на консоль, различные тесты и asserts, интерфейсы работы со связанными списками и пр. Все это нужно использовать.

Не нужно инкапсулировать стандартные интерфейсы в другие реализации обобщенных интерфейсов. Часто приходится сталкиваться с кодом, который переносится с других проектов, при этом на основе существующих интерфейсов реализуется некоторая громоздкая функция, которая служит для связи нового кода с существующим. Такое не нравится никому, поэтому необходимо непосредственно использовать предоставляемые интерфейсы.

Использование ресурсов

Менеджер памяти кучи

Активно используйте менеджер памяти кучи.

Почему нужно: очевидно, что без использования менеджера памяти кучи (который обеспечивает динамическое распределение ресурсов RAM) внедрить более или менее сложную бизнес-логику (например, оконный интерфейс или сетевой протокол) трудно, либо вообще невозможно.

Ускорение работы кода

Что надо сделать:

• убрать необоснованные задержки
• обоснованные задержки сократить до определенных стандартами величин
• минимизировать вывод на консоль
• реализовать, где возможно, режим verbose
• если где-то нужна задержка, то её можно запараллелить с той работой, которая от неё не зависит (например, инициализация ethernet с задержкой, а на её фоне активация дисков и чтение файловой системы).

Разделение ресурсов

Работу кода можно ускорить путем параллельного использования и разделения ресурсов.

При разделении ресурсов следует использовать различные средства синхронизации: спин-блокировки, семафоры, атомарные операции и пр.

Соглашения по кодированию

Использование директивы typedef

Определение нового типа с помощью оператора typedef имеет следующие недостатки:

• Определение нового типа через typedef скрывает истинную структуру данных
• Поскольку новый тип получается скрытым, то код более подвержен таким нехорошим вещам, как передача структуры данных в функцию по значению через стек

Конечно, существуют ситуации, в которых полезно использовать оператор typedef:

• сокрытие специфичных для аппаратной платформы деталей реализации или
• обеспечение совместимости при изменении типа

Поэтому нужно хорошо подумать, действительно ли оператор typedef необходим или он используется только для того, чтобы уменьшить количество символов при наборе кода.

Избегайте директив препроцессора ifdef в исходном коде

Использование директив ifdef в исходном коде не рекомендуется. Следует избегать делать что-нибудь вроде следующего:

…
#ifdef CONFIG_FOO 
       foo();
#endif
…

Вместо этого, если макрос CONFIG_FOO не определен, необходимо определять функцию fоо(), как ту, которая ничего не делает.

ifdef CONFIG_FOO
static int foo( void )
{
      /* .. */
}
#else
static inline int foo( void ) { }
#endif

После можно вызывать функцию fоо() без всяких условий. Пусть компилятор поработает за вас.

Но если все же без директивы ifdef вам не обойтись, то её следует использовать только на очень коротких участках кода.

При этом внутри тела функции ifdef не следует начинать с начала строки. То есть, её выравнивание должно подчинятся правилам окружающего кода.

Инициализация локалов и глобалов

Обязательно инициализируйте все переменные и массивы при их объявлении.

Все глобальные и локальные переменные функций (особенно в регистрах) должны быть обязательно чем-то проинициализированы.

Инициализация структур

Структуры необходимо инициализировать, используя метки полей. Это позволяет предотвратить некорректную инициализацию при изменении структур. Это также позволяет выполнять инициализацию не всех полей. К сожалению, в стандарте С99 принят довольно "страшненький" формат меток полей, а в компиляторе gcc ранее использовавшийся формат меток полей в стиле GNU признан устаревшим. Следовательно, для кода необходимо использовать новый формат согласно стандарту С99, каким бы ужасным он ни был.

struct foo rny_foo = 
{
    .а = INITIAL_A,
    .Ь = INITIAL_B,
}

Тут а и b — это поля структуры struct foo, а параметры INITIAL_A и INITIAL_B — соответственно их начальные значения.

Если поле не указано при инициализации, то оно устанавливается в свое начальное значение согласно стандарту ANSI С (указателям присваивается значение NULL, целочисленным полям — нулевое значение, а полям с плавающей точкой — значение 0.0 ).

Например, если структура struct foo также имеет поле int с, то это поле в предыдущем примере будет инициализировано в значение 0.

Да, это выглядит ужасно. Но у нас нет другого выбора.

Минимизация ассемблерных вставок

Некоторые проекты включают очень много ассемблерного кода, хотя без этого можно было бы спокойно обойтись.

Минимизация ассемблерных вставок нужна для улучшения читабельности кода. С учетом того, что C универсален, а ассемблер аппаратно зависим лучше, когда большая часть кода будет написана на C, а ассемблерные вставки будут только там, где это действительно уместно и нужно.

Что надо сделать: переписать всё на C, кроме глубоко аппаратных вещей. Вынести все ассемблерные вставки в ограниченное число файлов.

Избегайте ситуаций неявного преобразования типов

При явном приведении типа имя типа указывается в круглых скобках перед переменной или выражением. Например:

int  X       ;
int  Y = 200 ;
char C = 30  ;

     X = (int)C * 10 + Y; /// переменная С приводится к типу int

Неявное приведение типов происходит в следующих случаях:

• перед выполнением присваивания
• перед передачей аргумента функции
• перед возвратом функцией возвращаемого значения
• после вычисления выражения switch значение приводится к целому
• после вычисления выражений конструкций if, for, while, do-while значение приводится к типу bool
• после вычисления операндов бинарных арифметических, логических, битовых операций, операций сравнения, а также 2-го или 3-го операнда операции ?: значения операндов приводятся к одинаковому типу

Например, при выполнении бинарной арифметической операции значения операндов приводятся к одному типу. При наследовании указатели производного класса приводятся к указателям базового класса.

Пример на C:

double  d;  // вещественный тип
long    l;  // целый тип
int     i;  // целый тип

if ( d > i )      d  = i;
if ( i > l )      l  = i;
if ( d == l )     d *= 2;

При выполнении операций сравнения и при присваивании переменные разных типов неявно приводятся к одному типу.

При неявных преобразованиях возможны побочные эффекты. Например, при приведении числа вещественного типа к целому типу дробная часть отсекается (округление не выполняется). При обратном преобразовании возможно понижение точности из-за различий в представлении вещественных и целочисленных чисел. Например, в переменной типа float (число с плавающей точкой одинарной точности по стандарту IEEE 754) нельзя сохранить число 16 777 217 без потери точности, а в 32-х битной переменной целого типа int — можно. Из-за потери точности операции сравнения одного и того же числа, представленного целым и вещественным типами (например, int и float), могут давать ложные результаты (числа могут быть не равны).

#include 

int main ( void )
{
   int   i_value = 16777217;
   float f_value = 16777216.0;

         printf( "The integer is: %d\n", i_value            );
         printf( "The float is  : %f\n", f_value            );
         printf( "Their equality: %d\n", i_value == f_value );
}

Приведённый код выведет следующее, если размер int — 32 бита и компилятор поддерживает стандарт IEEE 754:

 The integer is: 16777217
 The float is  : 16777216.000000
 Their equality: 1

Нельзя полагаться на порядок вычисления аргументов

Поэтому не пишите код, который зависит от порядка вычислений аргументов функции. Необдуманные действия тут могут привести к неприятностям.

Пример:

void Transmogrify( int, int );
int  count = 5;

     Transmogrify( ++count, ++count ); /// Порядок вычислений неизвестен

Все, что можно сказать определенного, это то, что при входе в тело функции Transmogrify значение переменной count будет равно 7, но мы не можем сказать, какой аргумент будет равен 6, а какой — 7. Эта неопределенность остается и в гораздо менее очевидных случаях, таких как функции, модифицирующие свои аргументы (или некоторое глобальное состояние) в качестве побочного действия:

int Bump( int& x ) { return ++x; }

    Transmogrify( Bump(count), Bump(count) ); /// Результат неизвестен

Использование оператора return

Внутри функций и методов оператор return старайтесь вызывать только один раз. Лучше всего перед выходом из функции или метода (перед финальной закрывающей скобкой }).

Такой подход позволит вам отрабатывать реакцию по завершению функции (или метода) единообразно и в одном месте, например, при отладке.

Если функция возвращает значение, его можно запоминать в локальной переменной и затем вернуть в конце функции или метода.

Для внедрения сказанного выше можно использовать псевдокод try, throw и catch.

Код возврата

При успешном завершении функции или метода рекомендуется возвращать значение SUCCESS - 0 (ноль) в качестве кода возврата.

Для избежания путаницы не следует использовать другие значения кода возврата (значения, отличные от SUCCESS), как признаки успешного выполнения функции или метода.

Прочие требования

• не используйте магические константы
• используйте структуры и объединения для управления и манипулирования данными
• везде, где это возможно, используйте битовые поля вместо масок
• размещайте глобалы всего проекта в отдельном файле/файлах (например: global.h)
• при доступе к общим данным используйте setters и getters везде, где это возможно
• объявляйте переменные как можно локальнее, инициализируйте их при объявлении
• старайтесь не использовать глобальные переменные

• избегайте длинных функций и глубокой вложенности
• старайтесь не использовать препроцессор для задания определения функций
• активно используйте const
• используйте static для глобальных функций и переменных одного модуля

• проектируйте и пишите безопасный в отношении ошибок код
• проверяйте параметры функций и выходные данные на допустимость значений
• не жалейте сил на диагностику и проверяйте все, что можно проверить
• выдавайте предупреждения об ошибках везде и как можно раньше
• для верификации данных широко применяйте ассерты (asserts)
• для switch обязательно указывайте поведение по умолчанию (default)
• избавьте и не создавайте макросы и функции обертки, стабы, дублеры, заглушки
• повышенная диагностика для: IRQ, IPC, mm, syscalls, callbacks, drivers, libs

• предпочитайте малое большому и монолитному
• делайте данные-члены закрытыми
• не допускайте вмешательства во внутренние дела классов
• выделяйте или освобождайте ресурсы в одном месте
• предпочитайте операции с множествами операциям с отдельными элементами
• работайте с типами, а не с представлениями в памяти

• не используйте оператор goto
• стремитесь к максимальной простоте (линейный код + минимум ветвлений)
• устраняйте все предупреждения компилятора
• настраивайте проект так, чтобы он компилировался во всех вариантах сборки

• программируйте, заглядывая в будущее
• как в шахматах, постоянно улучшайте позицию и повышайте качество кода

Управления версиями кода


Система Subversion

Kscope IDE для C Linux исходников

kscope.jpg

При разработке исходного кода удобно использовать IDE - интегрированную среду разработки.

Интегрированная среда разработки (Integrated Development Environment или IDE) — система программных средств, применяемая программистами для разработки программного обеспечения.

Integrated Development Environment для C Linux

Основными критериями при выборе IDE для программирования на C Linux являются:
• мульти-проектность
• навигация по коду
• подсветка синтаксиса
• операции с текстом: поиск, замена, перемещение, удаление, вставка и пр.

Этим критериям удовлетворяет множество сред. Наиболее популярные: NetBeans, Eclipse, KDevelop, IDEA, Anjuta. Все эти оболочки включают в себя редактор, компилятор, отладчик, средства сборки проекта и многое другое.

Некоторые разработчики предпочитают им интегрированную среду разработки Kscope, которая, ни в коем случае, не предназначена для замены популярных IDE, таких как NetBeans, Eclipse или KDevelop.

Kscope не обеспечивает стандартный цикл разработки запись-компиляция-отладка, поддерживаемый большинством ведущих сред. Вместо этого, Kscope сфокусирована на редактировании и анализе исходных текстов.

Обзор Kscope

Kscope - бесплатная (freeware) IDE, которая включает мощный редактор исходных кодов. Она обеспечивает среду редактирования для большинства проектов на C и позволяет обрабатывать исходники, состоящие из тысяч строк (такие, как ядро Linux).

Kscope - это QT4 front-end для KDE Cscope. Последняя консольная утилита заточена на сканирование исходников и реализует поиск в коде символов, определений, объявлений, функций и файлов по заданному фрагменту текста или шаблону.

Cscope является инструментом Linux для просмотра исходного кода в терминальной среде. Первоначально она была предназначена для работы с C кодом, но также хорошо работает с ПО созданном на C++, Java, а также с проектами, которые написаны на некоторых других языках.

Kscope построена вокруг эффективного Cscope-механизма навигации по исходникам, который позволяет пользователю выполнять запросы к коду.

Типы Kscope запросов к коду могут включают в себя:
• поиск всех определений идентификатора
• поиск всех ссылок на идентификатор
• поиск функций, вызываемых этой функцией
• поиск функций, вызывающих эту функцию:
• поиск по шаблону
• переход к строке
• поиск и замену строки
• копирование, перемещение, удаление фрагмента кода
• поиск файлов по фрагменту имени
• поиск всех #include по фрагменту текста
• и пр.

Запросы к коду обрабатываются с помощью основного Cscope процесса. Kscope просто служит front-end средой к основному Cscope процессу, скармливает ему запросы и анализирует вывод. Результат анализа, в дальнейшем, может использоваться для перехода к соответствующей строке в редакторе кода.

Основные свойства:
• много-оконность (через использование вашего любимого KDE редактора)
• управление проектом
front-end к большинству запросов Cscope
• список тегов для каждого открытого редактора
• вызов дерева окон
• дерево папок
• управление сессиями, включая сохранение и восстановление запросов
• работа с внешне-построенными Cscope.out файлами
• окно последних файлов
• и пр.

Настройка Kscope

Для начала заходим в меню Settings->Configure Kscope. Выбираем вкладку Programmes, настраиваем пути (можно нажать на кнопку Guess, которая находится чуть ниже).

       Cscope path: /usr/X11R6/bin/cscope
       Cscope tags: /usr/X11R6/bin/exuberant-ctags
       Dot path:    /usr/X11R6/bin/dot  

Жмем OK

На своё усмотрение можно настроить цвета и шрифт в соответствующих вкладках Colours и Fonts.

Далее. Заходим в меню Settings->Configure Editor. Выбираем вкладку Open/Save.
Устанавливаем Encoding: в Cirillic ( koi8-r )

Далее. Заходим в Tools->Encoding.
Выбираем Cirillic ( koi8-r )

Создание Kscope проекта

Заходим в меню Project->New Project. И выполняем такие настройки:

Вкладка Details:
В поле Name вводим название своего проекта. В поле Path указываем путь к папке, в которой будет храниться файл вашего проекта.

В поле Source Root нужно указать путь к папке с теми файлами, которые вы хотите добавить в проект для редактирования, позже, при добавлении новых файлов, по умолчанию будет открываться именно эта папка.

Например:
Name KSCOPE
Path /home/lomako_g/hw3/allcpu/trunk/KSCOPE
Source Root /home/lomako_g/hw3/allcpu/trunk/

Жмем OK

Переходим на вкладку File Types:
Здесь мы выбираем тип файлов (расширения), которые нужно добавить в проект.

Выбираем в правой колонке нужный тип файла и нажимаем << Add, нужный нам тип появится в левой колонке. После того, как вы добавите все необходимые типы (например .c, .S, .cc и .h) и нажмите на OK.

Добавление файлов в проект Kscope

После нажатия OK, откроется окно Project Files, которое также можно вызвать из меню Projects->Add/Remove Files. В этом окне можно добавлять файлы для редактирования кода.

В поле Filter можно задать фильтр для добавляемых файлов. Например, если у вас в папке есть файлы .c, .S, .cpp, .cc и .h, то при указания фильтра .h, в проект добавятся только файлы с этим расширением.

Для того, чтобы добавить файлы, нужно кликнуть на любую из трёх кнопок:
Files - просто добавляет в проект файлы из папки, можете сами выбрать нужные файлы
Directory - после клика по папке в проект добавляются все файлы из папки
Tree - в проект добавятся файлы из всего дерева

Добавляем в проект выбранные файлы и жмем OK

Если вы захотите, чтобы можно было добавить файлы с другим расширением, то вам нужно зайти в Project->Properties, выбрать вкладку File Types и произвести уже знакомые вам действия.

Скачать Kscope

Kscope-1.6.2.tar.gz
Kscope-1.9.4.tar.gz

Пример кода в стиле РВН


/**
 *  @file       phy_s3.h
 *  @addtogroup DDR4_PHY
 *  @{
 *  @internal   Header. Поддежка режима энергосбережения (S3)   
 *  @see        /auto/da/technology/16/tsmc_cln16ffp/lib/synopsys/dwc_ddr43_phy/Latest/doc/  
 *  @brief      Integrator
 */
#ifndef PHY_S3_H
#define PHY_S3_H

/// =============================================================================
/// @include
/// =============================================================================
#include 

/// =============================================================================
/// @namespace extern 
/// =============================================================================
extern	uint8_t	no_stk	spmc_slp_typx_get	( uint64_t base );
extern	void	no_stk	reset_sleep_type_set	( u8 type       );

/// =============================================================================
/// @def
/// =============================================================================
#define	S3_LENGHT			( sizeof( SaveDDR ) 			)
#define	S3_VALUES			( &SaveDDR      			) 
#define	S3_is_phy_conf()		( runtimeConfig.RetEn			)
#define	S3_is_cmos_conf()		( TRUE == CMOS_get( phy.yRetEn )	)

#define	S3_reg_adr( cpu, ch, reg )	SaveDDR.aRetRegList[ cpu ][ ch ][ reg ].Address
#define	S3_reg_val( cpu, ch, reg )	SaveDDR.aRetRegList[ cpu ][ ch ][ reg ].Value
#define	S3_T1_val(  cpu, ch      )      SaveDDR.aTIM1      [ cpu ][ ch ].v
#define	S3_T2_val(  cpu, ch      )      SaveDDR.aTIM2      [ cpu ][ ch ].v

/// =============================================================================
/// @interface
/// =============================================================================
bool	no_stk	S3_detect		( void  ) ;
bool		S3_is_active		( void  ) ; 
int		S3_send_to_kernel	( void  ) ; 
bool		S3_exist		( void  ) ;
void    	S3_done			( void  ) ;     
bool	no_stk	S3_is_bt_conf		( void  ) ;
int		S3_show_ddr4_regs	( u8 ch ) ; 
void		S3_show_phy_reg		( u32 nReg, u32 pReg, u16 vTX, u16 vRX ); 

/// =============================================================================
/// @}                               @file EOF  
/// =============================================================================
#endif	/// @~ PHY_S3_H


/**
 *  @file       phy_s3.c
 *  @addtogroup DDR4_PHY
 *  @{
 *  @internal   Implementation. Поддежка режима энергосбережения (S3)   
 *  @see        /auto/da/technology/16/tsmc_cln16ffp/lib/synopsys/dwc_ddr43_phy/Latest/doc/  
 *  @brief      Integrator
 */

/// =============================================================================
/// @include
/// =============================================================================
#include "phy_s3.h"


/// =============================================================================
/// @interface
/// =============================================================================

/** 
 *  @brief	S3_is_bt_conf
 *  @internal	Определяет есть ли бит S3 в БТ регистре
 *  @param[in]	
 *  @return 	bool Флаг
 */
bool	no_stk	S3_is_bt_conf( void )
{		 
    #if defined(E2C3)
	if ( BT_REG_get_flag( CPU0, S3_BIT) != FALSE )	return TRUE  ;
	else						return FALSE ; 	
    #else	
	return FALSE ;
    #endif
} /// @~ „„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„ End Function


/** 
 *  @brief	S3_detect
 *  @internal	Детектирует наличие данных и состояния машины в режиме S3 
 *              Если данные есть, то уст. бит в BT регистре 
 *  @param[in]	
 *  @return 	bool Флаг
 */
bool	no_stk	S3_detect( void ) 
{		 
    #if defined(E2C3)
    	/// „„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„
    	/// @internal
    	/// ”””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””
	if ( spmc_slp_typx_get( SPMC_BASE_ADDR_GET) == SLP_TYP3_S3  &&  S3_is_cmos_conf() )
	{ 
		BT_REG_set_flag( CPU0, S3_BIT );
	}
	else 	BT_REG_nul_flag( CPU0, S3_BIT );

        reset_sleep_type_set( SLP_TYP0_S0 );		

	return  S3_is_bt_conf() ; 
    #else	
	BT_REG_nul_flag( CPU0, S3_BIT);			return FALSE ;
    #endif
} /// @~ „„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„ End Function


/** 
 *  @brief	S3_is_active    	
 *  @internal	Проверяет S3 в CMOSs и BT т.е S3 активен 
 *  @param[in]	
 *  @return 	bool Флаг
 */
bool		S3_is_active( void ) 
{		 
    #if defined(E2C3)  &&  defined(BUG146812)		/// Переход в ОС после выхода из состояния S3
	return	S3_is_cmos_conf()  &&  S3_is_bt_conf();	/// @~ Если разрешен S3 в CMOS и в BT
    #else
	return FALSE ;	 	 	
    #endif
} /// @~ „„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„ End Function


/** 
 *  @brief    	S3_send_to_kernel()
 *  @internal	Передает инфу о режиме энергосбережения S3 в Linux на E2C3
 *  @param[in]	
 *  @return     int err
 */
int S3_send_to_kernel( void ) 
{
    #if defined(E2C3) && defined(BUG135610) 				/// Проверка режима энергосбережения S3 на E2C3 
	boot_info_t * boot_info = &( boot_data.bootblock_p->info );
    	/// „„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„
    	/// @internal
    	/// ”””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””
	if ( S3_is_cmos_conf() )					/// @~ Если в CMOS разрешен режим энергосбережения S3 
	{  
	  #ifdef BUG135610_GEN						/// @bug Генерация бутом S3 на флэш и уст.бита в BN_REG
										 GOOD( FUNC, "FLASH_write" );
	   	 FLASH_write( NUM_NOR_MT25QU512, FLASH_ADDR_S3S4, 
                              S3_LENGHT, 	 S3_VALUES         );		 BT_REG_set_flag( CPU0, S3_BIT ); 
	  #else
										 GOOD( FUNC, "Set boot_info->bios.s3_..." );
	  #endif							
		boot_info->bios.s3_info.ram_addr = virt_to_phys( S3_VALUES );
		boot_info->bios.s3_info.rom_addr = FLASH_ADDR_S3S4          ;
		boot_info->bios.s3_info.size     = S3_LENGHT                ;
	}
	else
	{				    					 WARN( FUNC, "!FLASH_write" );
		boot_info->bios.s3_info.ram_addr = 0 ;
		boot_info->bios.s3_info.rom_addr = 0 ;
		boot_info->bios.s3_info.size     = 0 ;
	}
    #endif
} /// @~ „„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„ End Function


/** 
 *  @brief	S3_exist    	
 *  @internal	Проверяет существование
 *  @param[in]	
 *  @return 	bool Флаг
 */
bool		S3_exist( void ) 
{			   			GOOD2( "S3 yBT:", S3_is_bt_conf(), "yRT:", S3_is_phy_conf() );
    #if defined(E2C3) && defined(BUG135610)	/// I.Petrov: Проверка энергосбережения на E2C3  
        return 		   			( S3_is_bt_conf()  &&  S3_is_phy_conf() );
    #else
	return FALSE ;	 	 	
    #endif
} /// @~ „„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„ End Function


/** 
 *  @brief	S3_done    	
 *  @internal	Завершает обработку
 *  @param[in]	
 *  @return 	void
 */
void		S3_done( void ) 
{
    #if defined(E2C3) && defined(BUG135610) /// I.Petrov: Проверка энергосбережения на E2C3  
	if ( S3_exist() ) { 		    BT_REG_nul_flag( CPU0, S3_BIT);	GOOD( "End", "Hibernat" ); }
    	else									GOOD( "End", "!Hibernat"); 
    #endif
} /// @~ „„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„ End Function


/** 
 *  @brief	S3_show_phy_reg
 *  @internal	Печать адреса, индекса и значения PHY-регистра 
 *  @param[in]	u32 nReg, u32 pReg - Номер и адрес регистра  
 *  @param[in]	u16 vTX, u16 vRX   - Записанное и считанное значение регистра  
 *  @return 	void
 */
void		S3_show_phy_reg( u32 nReg, u32 pReg, u16 vTX, u16 vRX ) 
{															 
    if ( IsHW_AdvancedDiagnos() )
    {							ASSERT( nReg >= MAX_NUM_RET_REGS, "idx>=max", -EARG ); 
	if ( pReg == 0 && vTX == 0 && vRX == 0 )	return; 
	else						NEWS3( "Addr:", pReg, "Idx", nReg, "WR:", vTX );
	
	if ( vRX != vTX )			        _Warn( "!=RD:", vRX )
    }
} /// @~ „„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„ End Function


/** 
 *  @brief	S3_show_ddr4_regs
 *  @internal	Печать регистров DDR4, используемых в режиме S3 
 *  @param[in]	u8 ch
 *  @return 	void
 */
int		S3_show_ddr4_regs( u8 ch ) 
{							ASSERT( ch >= ddr4.mc.max, "mc.max<=mc", -EARG );
    if ( IsHW_AdvancedDiagnos() )
    {	
       u32 T1= MC_TIM1_let( ch, nCPU );   SHOW_IF( S3_T1_val( nCPU, ch)!=T1, "ERR S3.T1" );   MC_TIM1_print(T1);	 
       u32 T2= MC_TIM2_let( ch, nCPU );   SHOW_IF( S3_T2_val( nCPU, ch)!=T2, "ERR S3.T2" );   MC_TIM2_print(T2);
    }
} /// @~ „„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„ End Function


/// =============================================================================
/// @}                               @file EOF  
/// =============================================================================
 
/*
 * C portion of the SVC handler.  The SVC handler is split between an asm entry
 * and a C wrapper for simplicity of coding and maintenance.
 */
static void prvSVCHandler( uint32_t * pulRegisters ) __attribute__( ( noinline ) ) PRIVILEGED_FUNCTION;

#define OkTrain		0x07
#define NodeId 		0x7000

#define assign(ucn, val) ucn = val
#define ABS(x) (((x) < 0) ? -(x) : (x)) /* UNSAFE */

extern size_t popcount(uintmax_t);
const char *p;

#include 
void func(unsigned int ui_a, unsigned int ui_b) {
unsigned int usum;
if (UINT_MAX - ui_a < ui_b) {
/* Handle error */
} else {
usum = ui_a + ui_b;
}
/* ... */
}

void is_this_OK(void) {
 const char c_str[] = "Everything OK?";
 p = c_str;
 /* ... */
 p = NULL;
}

#include "stdlib.h"

struct flexArrayStruct {
 int num;
 int data[1];
};
void func(size_t array_size) {
 /* Space is allocated for the struct */
 struct flexArrayStruct *structP
 = (struct flexArrayStruct *)
 malloc(sizeof(struct flexArrayStruct)
 + sizeof(int) * (array_size - 1));
 if (structP == NULL) {
 /* Handle malloc failure */
 }
 
 structP->num = array_size;
 /*
 * Access data[] as if it had been allocated
 * as data[array_size].
 */
 for (size_t i = 0; i < array_size; ++i) {
 structP->data[i] = 1;
 }
}
/** @brief Determine the length (in bytes) of a null terminated string.
    @param pszStr   The null terminated string whose length is to be determined.
    @return The length of the @p pszStr string.
*/
static uint32_t RedStrLenUnchecked(
    const char *pszStr)
{
    uint32_t    ulLen = 0U;

    while(pszStr[ulLen] != '\0')
    {
        ulLen++;
    }

    return ulLen;
}

uint8_t RedFindVolumeNumber(
    const char     *pszVolume)
{
    uint32_t        ulNumber;
    uint8_t         bVolNum = REDCONF_VOLUME_COUNT;
  #if REDCONF_API_POSIX == 1
    uint8_t         bIndex;
  #endif

    /*  Determine if pszVolume can be interpreted as a volume number.
    */
    ulNumber = RedAsVolumeNumber(pszVolume);
    if(ulNumber != UINT32_MAX)
    {
        bVolNum = (uint8_t)ulNumber;
    }

  #if REDCONF_API_POSIX == 1
    /*  Determine if pszVolume is a valid path prefix.
    */
    for(bIndex = 0U; bIndex < REDCONF_VOLUME_COUNT; bIndex++)
    {
        if(strcmp(gaRedVolConf[bIndex].pszPathPrefix, pszVolume) == 0)
        {
            break;
        }
    }

    if(bIndex < REDCONF_VOLUME_COUNT)
    {
        bVolNum = bIndex;
    }
  #endif

    return bVolNum;
}
/* Reset the match pattern buffer */
#define Reset_Pattern(menu) \
  { (menu)->pindex = 0; \
    (menu)->pattern[0] = '\0'; }

#define UChar(c)	((unsigned char)(c))

#define NetPair(value,p)	(value).ext_color = (p), \
				AttrOf(value) &= ALL_BUT_COLOR, \
				AttrOf(value) |= (A_COLOR & COLOR_PAIR((p > 255) ? 255 : p))
#define SetPair(value,p)	(value).ext_color = (p)
#define GetPair(value)		(value).ext_color
#define unColor(n)		(AttrOf(n) & ALL_BUT_COLOR)

void GuidToStr(const Guid *guid, char *str, unsigned int buflen) {
  require(buflen >= GUID_STRLEN);
  require(snprintf(str, buflen,
    "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
     le32toh(guid->u.Uuid.time_low),
     le16toh(guid->u.Uuid.time_mid),
     le16toh(guid->u.Uuid.time_high_and_version),
     guid->u.Uuid.clock_seq_high_and_reserved,
     guid->u.Uuid.clock_seq_low,
     guid->u.Uuid.node[0], guid->u.Uuid.node[1],
     guid->u.Uuid.node[2], guid->u.Uuid.node[3],
     guid->u.Uuid.node[4], guid->u.Uuid.node[5]) == GUID_STRLEN-1);
}

int UTF16ToUTF8(const uint16_t *utf16, unsigned int maxinput,
                uint8_t *utf8, unsigned int maxoutput)
{
  size_t s16idx, s8idx;
  uint32_t code_point = 0;
  int code_point_ready = 1;  // code point is ready to output.
  int retval = CGPT_OK;

  if (!utf16 || !maxinput || !utf8 || !maxoutput)
    return CGPT_FAILED;
#define ReadDOC_(adr, reg)      ((unsigned char)(*(volatile __u32 *)(((unsigned 

static void addBitToStream(size_t* bitpointer, ucvector* bitstream, unsigned char bit)

	unsigned char ethaddr_str[sizeof("xx:xx:xx:xx:xx:xx")];

	ethaddr_to_string(ethaddr, ethaddr_str);

	if (is_valid_ether_addr(ethaddr)) {
		dev_info(&edev->dev, "got preset MAC address: %s\n", ethaddr_str);
		dev_set_param(&edev->dev, "ethaddr", ethaddr_str);
	}
void ip_to_string(struct in_addr x, char *s)
{
	x.s_addr = ntohl(x.s_addr);
	sprintf(s, "%d.%d.%d.%d",
		(int) ((x.s_addr >> 24) & 0xff),
		(int) ((x.s_addr >> 16) & 0xff),
		(int) ((x.s_addr >> 8) & 0xff),
		(int) ((x.s_addr >> 0) & 0xff)
	);
}

void vlan_to_string(ushort x, char *s)

static struct yaffsfs_Inode *yaffsfs_HandleToInode(int handle)
{
	struct yaffsfs_FileDes *fd = yaffsfs_HandleToFileDes(handle);

	if (fd && fd->handleCount > 0 &&
	    fd->inodeId >= 0 && fd->inodeId < YAFFSFS_N_HANDLES)
		return &yaffsfs_inode[fd->inodeId];

	return NULL;
}

static struct yaffs_obj *yaffsfs_HandleToObject(int handle)
     ui32Data     = pui32TraceBuf[ui32TracePtr];
     ui32DataToId = idToStringID(ui32Data);

     /* If an unrecognized id is found check if it is valid, if it is tracebuf needs updating. */
     if (ui32DataToId == RGXFW_SF_LAST  &&  RGXFW_LOG_VALIDID(ui32Data))
     {
	PVR_DUMPDEBUG_LOG("ERROR: Unrecognized id (%x). From here on the trace might be wrong!", ui32Data);
	return;
     }

     /* Update the trace pointer... */
     ui32TracePtr = (ui32TracePtr + 1) % RGXFW_TRACE_BUFFER_SIZE;
     ui32Count++;
} while ((RGXFW_SF_LAST == ui32DataToId  ||  ui32DataToId >= RGXFW_SF_FIRST)  

static const struct id_to_str arc_legacy_rel[] = {
static const struct id_to_str arc_cpu_rel[] = {
static void read_decode_ccm_bcr(struct cpuinfo_arc *cpu) 
#define IsLeap(y)  (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
#define IsLitState(s) ((s) < 7)
#define GetLenToPosState2(len) (((len) < kNumLenToPosStates - 1) ? (len) : 
#define Print(s)
#define PrintLn()
#define PrintHex(v, align)
#define PrintDec(v, align)
#define PrintAddr(p)

int nErrSet = DefErrSetWithSuffix(0, &bErrSet, 1, NULL, "_set");
static json_t * getVersions ( redfishService  *service,  const char *rootUri );
#define kHash2Size  (1 << 10)
pWriteBuffer = (UINT32 *)Buffer;
size_t          count,
int EFIAPI
sprintf_s (
  char        *str,
  size_t      sizeOfBuffer,
  char const  *fmt,
  ...
  )
LRESULT
CALLBACK
WinNtGopThreadWindowProc (
  IN  HWND    hwnd,
  IN  UINT    iMsg,
  IN  WPARAM  wParam,
  IN  LPARAM  lParam
  )
unsigned char    e_ident[EI_NIDENT]; /* File identification. */
Elf32_Half       e_type;             /* File type. */
Elf32_Half       e_machine;          /* Machine architecture. */

int a_guess_in_block = 0;
if (jtype != aLoopBlk && jtype != aOptBlk && jtype != aPlusBlk) {
#define aSubBlk			1
#define aOptBlk			2
#define aLoopBlk		3

void OutFirstSetSymbol(Junction *q, char * pSymbol)

#define SpecPos (-kStartOffset)
#define IsRep0Long (SpecPos + kNumFullDistances)
#define RepLenCoder (IsRep0Long + (kNumStates2 << kNumPosBitsMax))
#define LenCoder (RepLenCoder + kNumLenProbs)
#define IsMatch (LenCoder + kNumLenProbs)
#define Align (IsMatch + (kNumStates2 << kNumPosBitsMax))
#define IsRep (Align + kAlignTableSize)
#define IsRepG0 (IsRep + kNumStates)
#define IsRepG1 (IsRepG0 + kNumStates)
#define IsRepG2 (IsRepG1 + kNumStates)
#define PosSlot (IsRepG2 + kNumStates)
#define Literal (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
#define NUM_BASE_PROBS (Literal + kStartOffset)

#define NoSignal			0
#define MismatchedToken		1
#define NoViableAlt			2
#define NoSemViableAlt		3

/* MR7  Allow more control over signalling                                  */
/*        by adding "Unwind" and "zzsetSignal"                              */

#define Unwind              4
#define zzsetSignal(newValue) *_retsignal=_signal=(newValue)
#define zzsuppressSignal *_retsignal=_signal=0
#define zzexportSignal    *_retsignal=_signal

UINTN
EFIAPI
JsonObjectSize (
  IN    EDKII_JSON_OBJECT  JsonObject
  )
{
  return json_object_size ((json_t *)JsonObject);
}

/* tree duplicate */
AST *
#ifdef __USE_PROTOS
zzdup_ast(AST *t)
#else
zzdup_ast(t)
AST *t;
#endif
{
	AST *u;
	
	if ( t == NULL ) return NULL;
	u = zzastnew();
	*u = *t;
#ifdef zzAST_DOUBLE
	u->up = NULL;		/* set by calling invocation */
	u->left = NULL;
#endif
	u->right = zzdup_ast(t->right);
	u->down = zzdup_ast(t->down);
#ifdef zzAST_DOUBLE
	if ( u->right!=NULL ) u->right->left = u;
	if ( u->down!=NULL ) u->down->up = u;
#endif
	return u;
}

EFI_STATUS
AbortAsyncPassThruTasks (
  IN NVME_CONTROLLER_PRIVATE_DATA    *Private
  )
{
  EFI_PCI_IO_PROTOCOL                *PciIo;
  LIST_ENTRY                         *Link;
  LIST_ENTRY                         *NextLink;
  NVME_BLKIO2_SUBTASK                *Subtask;
  NVME_BLKIO2_REQUEST                *BlkIo2Request;
  NVME_PASS_THRU_ASYNC_REQ           *AsyncRequest;
  EFI_BLOCK_IO2_TOKEN                *Token;
  EFI_TPL                            OldTpl;
  EFI_STATUS                         Status;

  PciIo  = Private->PciIo;
  OldTpl = gBS->RaiseTPL (TPL_NOTIFY);

  //
  // Cancel the unsubmitted subtasks.
  //
  for (Link = GetFirstNode (&Private->UnsubmittedSubtasks);
       !IsNull (&Private->UnsubmittedSubtasks, Link);
       Link = NextLink) {
    NextLink      = GetNextNode (&Private->UnsubmittedSubtasks, Link);
    Subtask       = NVME_BLKIO2_SUBTASK_FROM_LINK (Link);
    BlkIo2Request = Subtask->BlockIo2Request;
    Token         = BlkIo2Request->Token;

    BlkIo2Request->UnsubmittedSubtaskNum--;
    if (Subtask->IsLast) {
      BlkIo2Request->LastSubtaskSubmitted = TRUE;
    }
    Token->TransactionStatus = EFI_ABORTED;

    RemoveEntryList (Link);
    InsertTailList (&BlkIo2Request->SubtasksQueue, Link);
    gBS->SignalEvent (Subtask->Event);
  }

  //
  // Cleanup the resources for the asynchronous PassThru requests.
  //
  for (Link = GetFirstNode (&Private->AsyncPassThruQueue);
       !IsNull (&Private->AsyncPassThruQueue, Link);
       Link = NextLink) {
    NextLink = GetNextNode (&Private->AsyncPassThruQueue, Link);
    AsyncRequest = NVME_PASS_THRU_ASYNC_REQ_FROM_THIS (Link);

    if (AsyncRequest->MapData != NULL) {
      PciIo->Unmap (PciIo, AsyncRequest->MapData);
    }
    if (AsyncRequest->MapMeta != NULL) {
      PciIo->Unmap (PciIo, AsyncRequest->MapMeta);
    }
    if (AsyncRequest->MapPrpList != NULL) {
      PciIo->Unmap (PciIo, AsyncRequest->MapPrpList);
    }
    if (AsyncRequest->PrpListHost != NULL) {
      PciIo->FreeBuffer (
               PciIo,
               AsyncRequest->PrpListNo,
               AsyncRequest->PrpListHost
               );
    }

    RemoveEntryList (Link);
    gBS->SignalEvent (AsyncRequest->CallerEvent);
    FreePool (AsyncRequest);
  }

  if (IsListEmpty (&Private->AsyncPassThruQueue) &&
      IsListEmpty (&Private->UnsubmittedSubtasks)) {
    Status = EFI_SUCCESS;
  } else {
    Status = EFI_DEVICE_ERROR;
  }

  gBS->RestoreTPL (OldTpl);

  return Status;
}

X86EMU_pioAddr  
_X86EMU_intrTab
xf86FindPciDeviceVendor 
pciSlotBX
pciReadByte
xf86Int10AllocPages
xf86HandleInt10Options(ScrnInfoPtr pScrn, int entityIndex)
EntityInfoPtr pEnt = xf86GetEntityInfo(entityIndex);
OptionInfoPtr

msgBlk_1D_DDR4_offset_to
msgBlk_2D_DDR4_offset_to(PmuRevision),
msgBlk_2D_DDR4_offset_to(DRAMFreq), 

#define BS_jmpBoot_OFFSET                0
#define BS_jmpBoot_LEN                   3
#define BS_OEMName_OFFSET                3
#define BS_OEMName_LEN                   8
#define BPB_BytsPerSec_OFFSET           11
#define BPB_BytsPerSec_LEN               2
#define BPB_SecPerClus_OFFSET           13
#define BPB_SecPerClus_LEN               1
#define BPB_RsvdSecCnt_OFFSET           14
#define BPB_RsvdSecCnt_LEN               2 

ddk7xx_edidReadMonitorExHwI2C
ddk750_edidReadMonitorEx

cpu_regs.h
    #define	E2K_RWP_stub1		fields.stub1
    #define	E2K_RWP_stub2		fields.stub2
    #define	E2K_RWP_stub3		fields.stub3
    #define	E2K_RWP_stub4		fields.stub4
    #define	E2K_RWP_stub5		fields.stub5
    #define	E2K_RWP_base		fields.base
    #define	E2K_RWP_reg		word 
    #define	_CUD_lo_rw	E2K_RWAP_lo_rw		/* [60:59] - read/write flags */ 
    typedef	e2k_rwp_struct_t	usbr_struct_t; // _t _s etc
    write_OSCUD_reg(oscud_struct_t OSCUD)
    read_OSGD_lo_reg(void) 
    
isLeap(__u32 year)  //fruid    

#define BS_jmpBoot_OFFSET                0
#define BS_jmpBoot_LEN                   3
#define BS_OEMName_OFFSET                3
#define BS_OEMName_LEN                   8
#define BPB_BytsPerSec_OFFSET           11
#define BPB_BytsPerSec_LEN               2
#define BPB_SecPerClus_OFFSET           13
#define BPB_SecPerClus_LEN               1
#define BPB_RsvdSecCnt_OFFSET           14
#define BPB_RsvdSecCnt_LEN               2
#define BPB_NumFATs_OFFSET              16
#define BPB_NumFATs_LEN                  1
 
int PlxDetermineNtPortSide(plx8xxx_dev *dev)
dev->PlxPortType = PLX_SPEC_PORT_UNKNOWN;
switch (dev->PlxFamily)	// TODO   

#define I2C_SR_RxACK	(1 << 7)	// Receive acknowledge from slave. '1' - no acknowledge received
#define I2C_AUX_SEND_TIMEOUT_ms     (50) 

	mode = getPowerMode(p);
void enable2DEngine(struct sm7xx_info* p, u32 enable)

 u32 usbsts_val = xhci_opreg_usbsts__get(xhci); 
 
uint16_t SequenceCtrl;     // Byte offset 0x10, CSR Addr 0x54008, Direction=In
uint8_t  HdtCtrl;          // Byte offset 0x12, CSR Addr 0x54009, Direction=In  


#define BPB_TotSec16_OFFSET             19
#define BPB_TotSec16_LEN                 2
#define BPB_Media_OFFSET                21
#define BPB_Media_LEN                    1 

#define csr_PllFreqSel_RANGE  4:0
#define csr_PllFreqSel_BITS   4:0
#define csr_PllFreqSel_MSB  4
#define csr_PllFreqSel_LSB  0 


    NextLink      = GetNextNode (&Private->UnsubmittedSubtasks, Link);
    Subtask       = NVME_BLKIO2_SUBTASK_FROM_LINK (Link);
    BlkIo2Request = Subtask->BlockIo2Request;
    Token         = BlkIo2Request->Token;

    BlkIo2Request->UnsubmittedSubtaskNum--;
    if (Subtask->IsLast) {
      BlkIo2Request->LastSubtaskSubmitted = TRUE;
    }
    Token->TransactionStatus = EFI_ABORTED;

add512(&(CTX->Sigma), (const union uint512_u *) data, &(CTX->Sigma)); 


    if (Subtask->IsLast) {
      BlkIo2Request->LastSubtaskSubmitted = TRUE;
    }
    Token->TransactionStatus = EFI_ABORTED;

    RemoveEntryList (Link);
    InsertTailList (&BlkIo2Request->SubtasksQueue, Link);
    gBS->SignalEvent (Subtask->Event);
  }

  //
  // Cleanup the resources for the asynchronous PassThru requests.
  //
  for (Link = GetFirstNode (&Private->AsyncPassThruQueue);
  
  Status = gBS->OpenProtocol (
                  Handle,
                  &gEfiBlockIoProtocolGuid,
                  (VOID **) &BlockIo,
                  This->DriverBindingHandle,
                  Controller,
  
if ( msgBlkPtr->EnabledDQs > 8*(userInputBasic.NumActiveDbyteDfi0) ||   


static jc42_DbLinked_list_t* create_jc42_DbLinkedList(){
	jc42_DbLinked_list_t* tmp = (jc42_DbLinked_list_t*)malloc(sizeof(jc42_DbLinked_l
 
static void pushBack(jc42_DbLinked_list_t *list, jc42_data_t *client) {  


int8_t WaitForConnection(plx8xxx_dev *dev);
void PlxNT_DetermineConnectType(plx8xxx_dev *dev);
int PlxNT_B2B_Initialize(plx8xxx_dev *dev);
int PlxPci_SetupNtTranslation(plx8xxx_dev *dev, uint8_t BarIndex, 

	uint32_t	RegUnErrMask;
	uint32_t	RegUnErrSeverity;
	uint32_t	RegPciCommand; 

send_msg(type, MSG_CS_SIR_Msg); 
#define DMA_TCS_TDMA_On 0x00020000   /* DMA_TCS:17: Transmit DMA On RO */
#define DMA_TCS_Tx_Rst  0x00000001   /* DMA_TCS:0:  Reset Transmitter R/W */
#define MSG_CS_SIR_Msg  0x00000002	/* MSG_CS:1: Send ID Request Message R/W */
#define MSG_CS_SGP0_Msg 0x00000008	/* MSG_CS:4: Send GP0 Message R/W */
#define MSG_CS_SGP1_Msg	0x0000000a	/* MSG_CS:5: Send GP1 Message R/W */
#define MSG_CS_SGP2_Msg	0x0000000c	/* MSG_CS:?: Send GP2 Message R/W */

void HDMI_Control_Packet_Auto_Send (struct sm7xx_info* p)
{
	writeHDMIRegister(p,  X42_AUTO_CHECKSUM, 0x01);	// enable auto checksum
	writeHDMIRegister(p,  X40_CTRL_PKT_EN, 0x00);
}

   if (ow_WriteCOM(portnum,1,sendpacket) == 0)
   {
#if defined(OW_DS2480_DEBUG)
     dbg_printf("\n\r%s():send the timing byte",__FUNCTION__);
#endif
   }else{
#if defined(OW_DS2480_DEBUG)
       	 dbg_printf("\n\r%s():WRITECOM_FAILED,send the timing byte");
#endif
       	 return OWERROR_WRITECOM_FAILED;
   }

ow_msDelay(10);//4
sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_WRITE1LOW | PARMSET_Write10us;
PARMSET_SampOff8us; 

#define HBCFG_IntegratedVgaEnable      (1<<1)
#define HBCFG_IntegratedGraphicsEnable (1<<0)  

//V9_sys.h
#define  NodeConfigApicIoPresentMask_high	23
#define  NodeConfigApicIoPresentMask_len	4
#define  NodeConfigApicNodePresentMask_high	19
#define  NodeConfigApicNodePresentMask_len	4
#define  NodeConfigCoreCmpMode				13
#define  NodeConfigCohModeHb				12
#define  NodeConfigCoreHardMask_high		11
#define  NodeConfigCoreHardMask_len			4
#define  NodeConfigIoLinkRdmaMode			7
#define  NodeConfigBootstrap                6
#define  NodeConfigBootMode                 5 

const __u64 dram_hole_size = (((__u64)node_reg_read(node, DRAM_Hole_Size)) & 
boot_data.boot_memory.mem_reg[0].size = Boot_Size_Max + ECHELON_Size_Max;
interfaces->initrd_base = ECHELON_LOAD_ADDR_VA + ECHELON_Size_Max; 
boot_data.heap_beg = Boot_RAM_PhA; 

int get_DramType(u8 node, u8 channel);
int get_DimmType(u8 node, u8 channel);
int get_NumDbyte(u8 node, u8 channel);
int get_NumActiveDbyteDfi0(u8 node, u8 channel);
int get_NumActiveDbyteDfi1(u8 node, u8 channel);
int get_NumRank_dfi0(u8 node, u8 channel);
int get_NumRank_dfi1(u8 node, u8 channel);
int get_PhyFreq(u8 node, u8 channel);
int get_DramDataWidth(u8 node, u8 channel);
uint8_t get_CsPresent(u8 node, u8 ch);
uint8_t get_CsPresentD0(u8 node, u8 ch);
uint8_t get_CsPresentD1(u8 node, u8 ch);
uint8_t	get_AddrMirror(u8 node, u8 channel); 

ow_SetBaudCOM(dev->portnum,newbaud); 
int PlxPci_SetupNtTranslation(plx8xxx_dev *dev, uint8_t BarIndex,
			uint64_t DistAddr, uint64_t LocalBarSize); 
   
int HDMI_Set_Mode (struct sm7xx_info* p, logicalMode_t *pLogicalMode, mode_parameter_t *pModeParam);
void HDMI_Enable_Output(struct sm7xx_info* p);   
if (lpDR_GID->HDR.byCmd == GIDCMD_GetInfo)  

EFI_STATUS EFIAPI efi_block_io_protocol__impl__ReadBlocks ( 

	uint8_t			BarNum;
	uint16_t		ReqId_Write;
	uint16_t		ReqId_Read;
	uint16_t		LutIndex;
	uint32_t		size;
	uint8_t			ScratchpadRegNum;
	uint32_t		BarOffset;
	uint32_t		RemotePhysAddr;
	uint32_t		RemoteBuffSize; 
 
#define BS_FAT12_16_BootSig_OFFSET      38
#define BS_FAT12_16_BootSig_LEN          1
#define BS_FAT12_16_VolID_OFFSET        39
#define BS_FAT12_16_VolID_LEN            4
#define BS_FAT12_16_VolLab_OFFSET       43
#define BS_FAT12_16_VolLab_LEN          11
#define BS_FAT12_16_FilSysType_OFFSET   54
#define BS_FAT12_16_FilSysType_LEN       8  

#define NodeConfig_BooteMode 		(1<<5)
#define NodeConfig_UseNodeCount 	(1<<4)
#define NodeConfig_CohModeL2		(1<<4)			/* 100412 instead UseNodeCount */
#define DRAM_Base_Offset	16
#define DRAM_Base_WE		2
#define DRAM_Base_RE		1
#define DRAM_Limit_Offset	16
#define DRAM_Limit_Mask		0x0fff	/*  => [39:24] */
#define DRAM_DstNode_Offset     0	/* DstNode 0-3:  this segment node-owner */ 

//boot_info
u64	targ_KERNEL_BASE;	/* KERNEL_BASE value  */ 

#define MCST_IDE_PCISTS_RPErr_SHIFT					8
#define SIC_PL_CSR_Link_Tu_BIT				(1 << SIC_PL_CSR_Link_Tu_SHIFT)
#define SIC_PL_CSR_Ch_On_BIT				(1 << SIC_PL_CSR_Ch_On_SHIFT)
#define SIC_PL_CSR_LErr_BIT					(1 << SIC_PL_CSR_LErr_SHIFT)
#define SIC_PL_CSR_SRst_BIT					(1 << SIC_PL_CSR_SRst_SHIFT)
			if (link_status & SIC_PL_CSR_LErr_BIT)
#define SIC_IO_CSR_Bsy_IE_SHIFT				4
#define SIC_IO_CSR_Err_IE_SHIFT				5
#define SIC_IO_CSR_Bsy_Ev_SHIFT				12
#define SIC_IO_CSR_Err_Ev_SHIFT				13
#define SIC_IO_CSR_TO_Ev_SHIFT				14
#define SIC_IO_CSR_Link_Tu_SHIFT			30
#define SIC_IO_CSR_Ch_On_SHIFT				31
   
#define NodeId_Node_Mask		 3 /* маска для любых полей NodeId */
#define NodeId_DefaultLink_Shift	12
#define NodeId_DefaultLink_Mask		0x3

typedef struct Reg_Addr_Val {
  uint32_t Address; ///< register address 
  uint16_t Value;   ///< register value 
} Reg_Addr_Val_t;
enum DrvType {
  DrvStrenFSDqP,  ///< 
  DrvStrenFSDqN,  ///< 
  ODTStrenP,      ///< 
  ODTStrenN,      ///< 
  ADrvStrenP,     ///< 
  ADrvStrenN      ///< 
};
extern int ARdPtrInitVal[4];

boot_data.image.base = Linux_Load_Addr;

#define Q_range 22:20
#define Q_min 0
#define Q_max 3
#define Q0 0x0 

#define Y_range 27:24
#define Y_min 0
#define Y_max 
#define Y0 0x0
#define Ybrd 0xf000000 

#define PHY_io_read16	dwc_ddrphy_phyinit_userCustom_io_read16
void PHY_print_out_ddr4(int Train2D) 

int PlxConfigureNtConnection(plx8xxx_dev * dev);
int8_t WaitForConnection(plx8xxx_dev *dev);
void PlxNT_DetermineConnectType(plx8xxx_dev *dev);
int PlxNT_B2B_Initialize(plx8xxx_dev *dev);
int PlxPci_SetupNtTranslation(plx8xxx_dev *dev, uint8_t BarIndex,
			uint64_t DistAddr, uint64_t LocalBarSize);    

#define PCI_TTY_Rx_Tx_MISC_PARS_WREG		4

#define Linux_Load_Addr			Linux_VA_Base 
#define Boot_Size_Max			(16 * MEGABYTE) 

#define xhci_capreg_ERST_Max(xhci)    

int PlxChipTypeDetect(plx8xxx_dev *dev);
int PlxDetermineNtPortSide(plx8xxx_dev *dev);
int PlxNtReqIdProbe(plx8xxx_dev *dev, bool bReadTlp, uint16_t *pReqId);
int PlxNtLutAdd(plx8xxx_dev *dev, uint16_t *pLutIndex,
				uint16_t ReqId, uint32_t flags);
int PlxScratchpadWrite(plx8xxx_dev *dev, int16_t RegNum, uint32_t value);
int PlxScratchpadRead(plx8xxx_dev *dev, int16_t RegNum, uint32_t *value);

int pciInit(void);
int pciExit(void); 

isLeap(__u32 year) 
           
#define RCode_32 	0x00000000
#define RCode_64	0x02000000
#define WCode_32 	0x04000000
#define WCode_64 	0x06000000
#define OCode_xx 	0x0ff00000 

EFI_STATUS
ReadNvmeControllerConfiguration (
  IN NVME_CONTROLLER_PRIVATE_DATA     *Private,
  IN NVME_CC                          *Cc
  )
{

VOID *Reserved; // Reserved. DO NOT USE.

// Image's load options
UINT32 LoadOptionsSize; // The size in bytes of LoadOptions. 

#define UC_mas			(0x66)
#define WC_mas			(0x60) 

AbortOpcode = NVME_ADMIN_ABORT_CMD,

#define EndInit			0x00
#define EndWrLvl		0x01
#define EndRdEnTrain		0x02
#define EndRdDelay		0x03
#define EndWrDelay		0x04
#define End2DRdDelay		0x05
#define End2DWrDelay		0x06
#define OkTrain			0x07
#define StreamMsgMode		0x08
#define EndRdLatencyTrain	0x09
#define EndRdDQTrain		0x0a
#define EndLRDIMMTrain		0x0c
#define EndCATrain		0x0d
#define EndMPRRDelay		0xfd
#define EndWrLvlDelay		0xfe
#define ERRTrain		0xff 

#define NodeDRAMBase 		0x7084		/* Node DRAM Base */ 
#define NodeId 		0x7000
#define NodeConfig 	0x7004
#define NodeConfig2	0x70b4
#define NodeID 		0x7000
#define RouteTbl0	0x7010
#define RouteTbl1	0x7014
#define RouteTbl2	0x7018
#define RouteTbl3	0x701C

Регистр CMD_MGA25 - управляющий регистр устройства.
Смещение 0x04 B.
Размер 2 B.
разряды	режим	default	описание
0	RW	0	IoEn — разрешение устройству реагировать на обращения в пространство PCIIO
1	RW	0	MemEn — разрешение устройству реагировать на обращения в пространство PCIMEM
2	RW	0	BmEn — разрешение устройству выдавать upsteam DMA обращения
3	RO	0	ScEn — special cycle игнорируется
4	RO	0	MwiEn — команда PCI memory write and invalidate не поддерживается
5	RO	0	VpsEn — video palette snooping не поддерживается
6	RW	0	ParErrEn — разрешение реагировать на ошибки четности:
7	RO	0	AdStepEn — address stepping не поддерживается
8	RO	0	SerrEn — ошибка SERR не поддерживается
9	RO	0	FastB2BEn — fast back-to-back транзакции не поддерживаются
10	RW	0	InterruptDisable — запрещение выдачи прерываний 
15:11	RO	0	Резерв.
/**
 * @file  	mc_mon_ctl_reg.c
 * @addtogroup	MC_MON
 * @{
 * @brief    	MC_MON_CTL (MC Monitor #0 Counter low)
 * @internal	Header.	
 * @link     	http://www.lab.sun.mcst.ru/honey/elbrus_16c/doc/hw/mc/e16_mc_config.pdf
 * @author   	msct.ru
 * @class 	MC_MON_CTL
 */
#if defined(E16C) 

/// =============================================================================
/// @include
/// =============================================================================
#include 

/// =============================================================================
/// @internal 
/// =============================================================================
///

/// =============================================================================
/// @interface 
/// =============================================================================

/// ------------------+-------------------------------+----------------------------------+-----+
/// @struct reg.flds  |             ATR               |                GET               | SET |
/// ------------------+------------+----+---+----+----+-------+------+-----+----+----+---+-----+
///                   | name       |dflt|spd|cmos|hard|  dflt | conv | spd |cmos|hard|val|  val|
///                   +------------+------------------+-------+------+-----+----+----+---+-----+
MC_f Rmon_ctl      ={{"MC_MON_CTL" ,   0, -1, -1 , -1 },{ 0   , 0    , 0   , 0  , 0  , 0 },{ 0 }};
MC_f Frst0         ={{"rst0"       , OFF, -1, -1 , -1 },{ 0   , 0    , 0   , 0  , 0  , 0 },{ 0 }};
MC_f Frst1         ={{"rst1"       , OFF, -1, -1 , -1 },{ 0   , 0    , 0   , 0  , 0  , 0 },{ 0 }};
MC_f Ffrz0         ={{"frz0"       ,  ON, -1, -1 , -1 },{ 0   , 0    , 0   , 0  , 0  , 0 },{ 0 }};
MC_f Ffrz1         ={{"frz1"       ,  ON, -1, -1 , -1 },{ 0   , 0    , 0   , 0  , 0  , 0 },{ 0 }};
MC_f Fld0          ={{"ld0"        , OFF, -1, -1 , -1 },{ 0   , 0    , 0   , 0  , 0  , 0 },{ 0 }};
MC_f Fld1          ={{"ld1"        , OFF, -1, -1 , -1 },{ 0   , 0    , 0   , 0  , 0  , 0 },{ 0 }};
MC_f Fes0          ={{"es0"        , 0x0, -1, -1 , -1 },{ 0   , 0    , 0   , 0  , 0  , 0 },{ 0 }};
MC_f Fes1          ={{"es1"        , 0x0, -1, -1 , -1 },{ 0   , 0    , 0   , 0  , 0  , 0 },{ 0 }};
MC_f Flb0          ={{"lb0"        , 0x0, -1, -1 , -1 },{ 0   , 0    , 0   , 0  , 0  , 0 },{ 0 }};
MC_f Flb1          ={{"lb1"        , 0x0, -1, -1 , -1 },{ 0   , 0    , 0   , 0  , 0  , 0 },{ 0 }};
MC_f Rmon_ctl_sentinel={ 0 } ;  
/// --------------------------------------------------------------------------------------------------------------------------- ///


/** 
 *  @brief	MC_MON_CTL_show()
 *  @internal	Печать регистра
 *  @param[in]	u8 cpu, u8 channel
 *  @return 	Register Value	
 */
int 	no_stk	MC_MON_CTL_show( u8 cpu, u8 ch )
{
	MON_CTL_t  mon_ctl_r = { .v = MC_MON_CTL_let( ch, cpu ) };    /// @~ Читаем содержимое регистра
	/// „„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„
	/// @internal
	/// ”””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””
	_NEWS( "Rd MC", ch );
	
	MSG( Rmon_ctl.v.name );  Note( "=", (u32)mon_ctl_r.v      ) ; /// @note Печать регистра целиком
	MSG( Frst0   .v.name );  Echo( "=", (u8) mon_ctl_r.s.rst0 ) ; /// @note Печать регистра по полям 
	MSG( Frst1   .v.name );  Echo( "=", (u8) mon_ctl_r.s.rst1 ) ; 
	MSG( Ffrz0   .v.name );  Echo( "=", (u8) mon_ctl_r.s.frz0 ) ; 
	MSG( Ffrz1   .v.name );  Echo( "=", (u8) mon_ctl_r.s.frz1 ) ; 
	MSG( Fld0    .v.name );  Echo( "=", (u8) mon_ctl_r.s.ld0  ) ; 
	MSG( Fld1    .v.name );  Echo( "=", (u8) mon_ctl_r.s.ld1  ) ; 
	MSG( Fes0    .v.name );  Echo( "=", (u8) mon_ctl_r.s.es0  ) ; 
	MSG( Fes1    .v.name );  Echo( "=", (u8) mon_ctl_r.s.es1  ) ; 
	MSG( Flb0    .v.name );  Echo( "=", (u8) mon_ctl_r.s.lb0  ) ; 
	MSG( Flb1    .v.name );  Echo( "=", (u8) mon_ctl_r.s.lb1  ) ; 

	return mon_ctl_r.v ;
} /// @~ „„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„ End Function


/** 
 *  @brief	MC_MON_CTL_init()
 *  @internal	Получает и записывает инициализационное значение в регистр 
 *  @param[in]	u8 cpu, u8 ch
 *  @return 	Register Value	
 */
u32 	no_stk	MC_MON_CTL_init( u8 cpu, u8 ch )
{                                                  ASSERT( cpu >= CPU_TOTAL, "cpu>3", 0 );
	MON_CTL_t  mon_ctl_r ;
	/// „„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„
	/// @internal
	/// ”””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””””
	mon_ctl_r.s.rst0	= MC_fGet( cpu, ch, &Frst0	) ;
	mon_ctl_r.s.rst1	= MC_fGet( cpu, ch, &Frst1	) ;
	mon_ctl_r.s.frz0	= MC_fGet( cpu, ch, &Ffrz0	) ;
	mon_ctl_r.s.frz1	= MC_fGet( cpu, ch, &Ffrz1	) ;
	mon_ctl_r.s.ld0		= MC_fGet( cpu, ch, &Fld0	) ;
	mon_ctl_r.s.ld1		= MC_fGet( cpu, ch, &Fld1	) ;
	mon_ctl_r.s.es0		= MC_fGet( cpu, ch, &Fes0	) ;
	mon_ctl_r.s.es1		= MC_fGet( cpu, ch, &Fes1	) ;
	mon_ctl_r.s.lb0		= MC_fGet( cpu, ch, &Flb0	) ;
	mon_ctl_r.s.lb1		= MC_fGet( cpu, ch, &Flb1	) ;

	MC_MON_CTL_put( ch, mon_ctl_r.v, cpu ) ; /// @note Запишем новое значение в регистр

	return mon_ctl_r.v ;
} /// @~ „„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„„ End Function


/// =============================================================================
/// @}                               @file EOF  				
/// =============================================================================
#endif	/// @~ if defined(E16C) 

Имена в С/C++, использующиеся для переменных, типов, функций, меток и других определяемых пользователем объектов, называются идентификаторами.

Данный раздел предназначен для обзора основных соглашений о формальном формировании имен идентификаторов.

РВН соглашения об идентификаторах

При вводе нового идентификатора в проект нужно/желательно/рекомендуется учитывать следующие факторы:
мнемоническое значение: идентификатор должен легко запоминаться
смысловое значение: роль идентификатора должна быть ясна из его названия
преемственность: желательно чтобы похожие объекты имели похожие имена
скорость разработки ПО: придумывание, ввод и редактирование идентификатора не должны занимать слишком много времени, имя не должно быть слишком длинным.

Выбор имен может стать задачей, поглощающей лишнее время у разработчика. Часто идентификатор, удовлетворяющий одним условиям противоречит другим. Кроме того, поддержать преемственность имен иногда бывает достаточно трудно.

Cоглашения об РВН-идентификаторах обеспечивают удобную технологию для формирования имен, удовлетворяющих вышеупомянутым критериям. Основной идеей является обеспечение компактности идентификаторов, их читабельности/описательности и передача основных характеристик идентификаторов как части имени.

Написание и регистр символов в именах идентификаторов должны отличаться от всех ключевых слов языка. Любой идентификатор можно уточнить однобуквенным РВН-префиксом/постфиксом.

РВН стандарт различает четыре типа идентификаторов:
   • Глобальные - они используются всем проектом в целом
   • Внутрифайловые - используются только в рамках файлов для которых они объявлены
   • Внутримодульные - используются лишь в внутри модулей/пакетов/классов/групп где они объявлены
   • Макросы - как правило цифровые и строковые

Глобальные идентификаторы декларируются вне функции. Они видны из любой части программы при наличии спецификатора extern. Глобальные идентификаторы (если они действительно нужны) должны быть описательными. Если у вас есть функция, которая выдаёт количество активных ядер у ЦП, то назвать её foo или cntactivecorescpu — это контрпродуктивно.

Конечно можно назвать её g_get_quantity_active_cores_for_cpu, но более оптимальным и компактным все же будет имя qGetActiveCoresForCpu. Имена со знаками подчеркивания в начале и/или конце зарезервированы для глобальных и системных идентификаторов и не должны применяться для каких-либо иных целей.

Внутрифайловые идентификаторы включают статические имена описанные вне функций, локальные и статические декларации описанные внутри функций, а также идентификаторы объявленные вне функций без спецификатора static, но используемые только внутри файлов где они объявлены.

Внутримодульные идентификаторы аналогичны Внутрифайловым, но оформляются в ином стиле и применяются лишь внутри ФАЙЛОВ МОДУЛЕЙ, в которых они объявлены. Их нотация понравится приверженцам ООП стиля. Имя класса тут выделено и отделено от метода или свойства не точкой '.', а символом '_'. То есть, если вы создаёте свои собственные модули, то идентификаторы в них, начинайте с имени модуля в CAPS или PascalCase стиле, который определяет модуль/пакет/класс/группу, к которому (которой) идентификаторы принадлежат.

Макросы должны кодироваться ЗАГЛАВНЫМИ БУКВАМИ. Их нотация подойдёт поклонникам классики. Декларация макросов заглавными буквами поддерживается почти всеми стандартами оформления кода на Cи. Рекомендуется (как правило или чаше всего) применять эту нотацию к строковым или цифровым макросам. Имена макросов в нижнем регистре приемлемы только в том случае, если макросы ведут себя как вызовы функций.

К идентификатору любого типа может добавляться однобуквенный префикс и/или постфикс.

Смешанный РВН стандарт лаконичен и включает четыре специализированных стиля именования, см. таблицу ниже.

ИМЯ ДЕКЛАРАЦИИ СТИЛЬ ПРИМЕРЫ
Глобальные идентификаторы
для всего проекта:
макросы, функции,
переменные, структуры и пр.

1).PascalCase -рекомендуемый.
Такой стиль глобалов сам по себе уже не
требует добавления к ним префикса 'g'.
2). snake_case

Echo( h, v )
_Echo( h, v )
Note( h, v )
IsStr
GetItems
GetAmountItems
Query
MyStruct_s
MyStruct_t
MyStruct_u
MyStruct_e
gDevList
qGetActiveCoresForCpu
__FILE__
va_end
va_start
memcpy
_fmemcpy
size_t
Внутрифайловые идентификаторы::
макросы, функции,
переменные, структуры и пр.

1). snake_case -рекомендуемый,
2). lowerPascalCase

max_items
note_table
cpu_a
cpu
node
idr_shift
idr_bit
getMaxItems
setMaxItems
get_max_items
set_max_items
nMaxItems
max_items
cntMaxItems
aPciItems
query
a_query
node_struct
node_s
node_t
node_e
node_u
Внутримодульные идентификаторы
модулей/пакетов/классов/групп:
макросы, функции,
переменные, структуры и пр.

1). CAPS_snake_case -рекомендуемый
Не запрещено:
2). CAPS_lowePascalCase
3). PascalCase__snake_case
4). PascalCase_lowePascalCase

PHY_show_all_regs( u8 cpu )
PHY_ShowAllRegs( u8 cpu )
MC_get_ctl_register( u8 cpu )
MC_getCtlRegister( u8 cpu )
PHY_GetItem( u8 cpu )
PHY_getItem( u8 cpu )
MC_initAllRegs( u8 node )
MC_init_all_regs( u8 node )
yMGA2XX_change_via_console()
MC_CTL_t
MC_CTL_r
Макросы.
Цифровые, строковые, глобальные
и внутренние.

В верхнем регистре -UPPER CASE

NODES
CPU_TOTAL
MC_TOTAL
MAX_NODE_NUM
CHAR_BITS
MAX_ITEMS
MAXVAL
WELCOME
Вопрос. Что делать если стиль чужого интегрируемого кода не соответствует нотации РВН? Например, при портировании PHY-DDR4 от SYNOPSYS их стандарт кодирования предлагает/позволяет имена функций в стиле dwc_ddrphy_phyinit_userCustom_J_enterMissionMode. Это естественно противоречит нотации РВН.

Ответ. Ничего не делать. Как отмечалось во введении, в случае наличия противоречий при интеграции чужого готового кода лучше следовать его стилю и оставить отступы, интервалы, комментарии, соглашения об именах, как это сделано в портируемом проекте, чем слепо следовать нотации РВН . "Тем более, что такой подход также разрешен и приветствуется в самом РВН стандарте".

Список префиксов и постфиксов

Префиксы и постфиксы

В РВН запрещено использовать в именах много-буквенные префиксы и постфиксы. Поэтому РВН стиль - это не венгерская нотация и не надо их путать.

В РВН, для информативного и краткого кодирования, рекомендуется (и можно) использовать в именах только одно-буквенные префиксы и постфиксы из следующего списка:

Pre_ , _Pos Тип
   

A, a, a_ , _a Array

B, b, b_ , _b Byte unsigned char, u8

C, _c Class

c, c_ char, Literal, Letter, Character signed char, char, s8

D, _d Dot, Double.    Real floating-point type (64 bits) Double

d, d_ dot.    Real floating-point type (32 bits) Float

E Error, Bug, Fail, Failure, Invalid

e, e_, _e enum enum

F, f, f_, _f Field, File, Feature, Attribute, Property, Member, Fluent/Float

G, g , g_, _g Global

H, h , h_, _h Header, Descriptor

I Item, Element, Cell, Entry, Entity, Interface

i, i_, _i integer, Index int

J, j , j_, _j Job, Task

K, _k Kernel

k, k_, Константа

L, _l List

l , l_ long long

M, m , m_, _m Method, Function, Procedure, Routine, Subroutine

N, n, n_, _n Numeric, Number unsigned int, unsigned char, unsigned long

O, o , o_, _o Object

P, p , p_, _p Pointer, Position, Point, Address, Link, Cursor, Location, Coordinates

Q, _q Queue, Table, List

q , q_, quantity, Amount, Number

R, r , r_, _r Register, Record, Rec, Row, Registering, ROM, Registry, paRt, paRtition, entRy, enteR, membeR, Cell, Item, Section, Component, Раздел

S, _s Struct

s, s_ signed

T, _t Type

t, t_ text, String, Message, Letter, Char, Character, Symbol

U, _u Union union

u, u_ unsigned unsigned

V, v, v_, _v Value, Var, Variant, Void, Volume

W, _w Window, Screen, Display, Message, Screen-Output

w , w_, word

Y, y , y_, _y Yes/No Bit, Flag bool, boolean

X, x , x_, _x eXception, Interrupt, Trap, Event, CallBack

Z, z , z_, _z siZe, Num\Diapason, Zone, Range, Capacity, Dimension, Volume, Quantity, Amount, Weight

 

При этом, как вы видите постфикс, а также префикс с большой заглавной буквы чаще всего обозначают тип переменной.

Примеры 1: aTypes, oFRUID, cpu_e, IPCC_CSR_t
Примеры 2: DVal64, val64_d, dVal32, d_val32

Примеры:


struct lcd_dev_s oLcdDev;

Примеры некоторых реализованных РВН проектов:

AO МЦСТ, Россия
Ген.директор: Ким Александр Киирович
mcst.ru
Проект: Микропроцессоры Эльбрус. Разработка Программы Начального Старта (зазручик)
GeeksForLess Inc., Canada 
Igor E. Nikolaichuk
geeksforless.com
Проект: Почтовый AntiSpam сервер для IIS6/IIS 
GeeksForLess Inc., Canada
Igor E. Nikolaichuk
geeksforless.com
Проект: PHP Framework проектирования web-приложений
DataDomain Inc., USA 
Основатели: Кай Ли, Брайан Байлз
datadomain.com
Системы хранения/дедупликации и решения в области резервного копирования и восстановления данных 
Проект: Offline Diagnostics Master - platform for troubleshooting of Data Domain products 
Компания "Крокус-Ком", Украина 
Ген.директор – Чередников Сергей Олегович 
crocuscom.com
Разработка и производство аппаратно-программных комплексов телекоммуникаций.
Проект: МикроОС для комплексов АПУС-АОН городских и сельских АТС 
Научно-производственная фирма "Гиацинт", Украина
Руководитель - Баранов Владимир Петрович.
Проект: Разработка ПО для микропроцессорных аппаратно-программных комплексов связи
ЦНИИ Комета, СССР
Директор: А.Савин. 
corpkometa.ru
Проект: ОСРВ на базе многопроцессорного вычислительного комплекса (МВК) Эльбрус-1

 ▤  ИНДИЯ И КИТАЙ ПОМОГУТ АСАДУ! США В СТУПОРЕ
 ▤  Ту160М2 — смертоносный Белый Лебедь
 ▤  Список софт-каталогов. с регистрацией через PAD.xml
 ▤  Что первично? Материя или Разум