Подтвердить что ты не робот

Стандарты кодирования для чистого C (не С++)

Я исхожу из фона java (из моих классов CS) и семестра С++. Я просто заканчиваю проект OpenCV для своего Co-Op, который в чистом C, поэтому я немного поздно задаю этот вопрос.

Каковы процессы проектирования и стандарты кодирования для чистого C?

Я знаком с объектно-ориентированным программированием, дизайном и лучшими практиками. Я немного растерялся на не-объектно-ориентированном языке, таком как C. Каждая отдельная переменная и функция кажутся глобальными. Это заставляет меня чувствовать себя настоящим беспорядком.

4b9b3361

Ответ 1

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

Я лично рекомендую Indian Hill C Style Guide с некоторыми изменениями. Кроме того, вы можете приобрести книгу Интерфейсы и реализации C, если у вас возникают проблемы при разработке крупномасштабных программ на C.

Ответ 2

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

Ответ 3

У меня нет профессионального опыта на C (только на С++), поэтому не слишком серьезно относитесь к моим советам, трюкам и советам, поскольку они "ориентированы на объекты".

Почти объект C?

Имитация основных объектно-ориентированных функций может быть легко выполнена:

В заголовке вперед объявите свой тип, typedef и объявите "методы". Например:

/* MyString.h */

#include <string.h>

/* Forward declaration */
struct StructMyString ;

/* Typedef of forward-declaration (note: Not possible in C++) */
typedef struct StructMyString MyString ;

MyString *       MyString_new() ;
MyString *       MyString_create(const char * p_pString) ;
void             MyString_delete(MyString * p_pThis) ;
size_t           MyString_length(const MyString * p_pThis) ;

MyString *       MyString_copy(MyString * p_pThis, const MyString * p_pSource) ;
MyString *       MyString_concat(MyString * p_pThis, const MyString * p_pSource) ;

const char *     MyString_get_c_string(const MyString * p_pThis) ;
MyString *       MyString_copy_c_string(MyString * p_pThis, const char * p_pSource) ;
MyString *       MyString_concat_c_string(MyString * p_pThis, const char * p_pSource) ;

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

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

В исходном файле определите свой тип и определите функции:

/* MyString.c */

#include "MyString.h"

#include <string.h>
#include <stdlib.h>

struct StructMyString
{
   char *      m_pString ;
   size_t      m_iSize ;
} ;

MyString * MyString_new()
{
   MyString * pMyString = malloc(sizeof(MyString)) ;

   pMyString->m_iSize = 0 ;
   pMyString->m_pString = malloc((pMyString->m_iSize + 1) * sizeof(char)) ;
   pMyString->m_pString[0] = 0 ;

   return pMyString ;
}

/* etc. */

Если вы хотите "private" функции (или частные глобальные переменные), объявите их статическими в источнике C. Таким образом, они не будут видны снаружи:

static void doSomethingPrivate()
{
   /* etc. */
}

static int g_iMyPrivateCounter = 0 ;

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

Разное. Советы

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

Например, несколько возвратов являются рискованными. Например:

void doSomething(int i)
{
   void * p = malloc(25) ;

   if(i > 0)
   {
      /* this will leak memory ! */
      return ;
   }

   free(p) ;
}

Избегайте неконстантных глобальных переменных

Сюда входят "статические" переменные (которые не являются статическими функциями).

Глобальные неконстантные переменные почти всегда являются плохими идеями (т.е. см. C API strtok для примера дрянной функции), и при создании многопоточного безопасного кода они являются болью для обработки.

Избежать столкновения имен

Выберите "пространство имен" для ваших функций и для ваших определений. Это может быть:

#define GROOVY_LIB_x_MY_CONST_INT 42

void GroovyLib_dosomething() ;

Beware определяет

Определения не могут быть исключены в C, но они могут иметь побочные эффекты!

#define MAX(a, b) (a > b) ? (a) : (b)

void doSomething()
{
   int i = 0, j = 1, k ;
   k = MAX(i, j) ;   /* now, k == 1, i == 0 and j == 1 */
   k = MAX(i, j++) ; /* now, k == 2, i == 0 and j == 3, NOT 2, and NOT 1 !!! */
}

Инициализировать переменные

Избегайте объявления переменных без их инициализации:

int i = 42 ; /* now i = 42 */
int j ;      /* now j can have any value */
double k ;   /* now f can have any value, including invalid ones ! */

Неинициализированные переменные являются причинами болезненных ошибок.

Знать все API C

Список функций API C, как описано в K & R, довольно мал. Вы прочтете весь список за 20 минут. Вы должны знать эти функции.

Хотите испытать?

Перепишите API C. Например, попробуйте написать собственную версию функций string.h, чтобы посмотреть, как это делается.

Ответ 4

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

В противном случае типичная идиома, которую я вижу для избежания конфликтов пространства имен, заключается в том, чтобы поместить на имя какой-то идентификатор объекта. Например, все в foo.c можно назвать foo _ *

Ответ 5

Работайте с другими хорошими программистами C. Просматривайте код с ними. Не только пусть они смотрят на ваш код, но вы смотрите на их код.

Ответ 6

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

Сначала прочитайте книгу о программировании и стиле С, K & R в порядке. Во-вторых, я бы рекомендовал проверить CERT Programming Standard. Несмотря на то, что этот сайт в основном ориентирован на "безопасные" стандарты кодирования, большая часть контента здесь - это общие стандарты качества кода, которым должны следовать все. Выполнение упомянутых здесь вещей улучшит ваше качество, устранит жутких ошибок и, как побочный эффект, сделает ваш код более безопасным.

Ответ 7

Возможно, вам захочется хорошенько взглянуть на исходный код ядра Linux..... Кстати, это не самый простой кусок кода, с которого можно начать, но поскольку вы работаете в фоновом режиме, это может помочь... Как объект Ориентированный программист, вы можете найти обработку ошибок в C трудной задачей. Это может быть helps---> http://www.freetype.org/david/reliable-c.html

Ответ 8

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

Это помогает, если имя class является префиксом имени функции, и если все частные функции и данные класса объявлены static. Вы создаете конструкторы с malloc() для получения памяти и явной инициализации полей данных.

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

За этим шаблоном следует несколько библиотек. Функция инициализации возвращает куки файл, который должен быть возвращен ко всем библиотечным методам, а один метод служит деструктором.

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

Ответ 9

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

Например:

/** foo.c */
static void foo_helper() {...} /* foo_helper cannot be called by name 
                                  outside of foo.c */
static int local_state;        /* local state is visible at file scope,
                                  but is not exported to the linker */

Ответ 10

Стиль кодирования

Systemd

инструменты качества системного кода

RIOT-OS

Nginx

Руководство по Git Source

FFmpeg

локон

Архитектура

Архитектура приложений с открытым исходным кодом Программы C включают в себя Git, Nginx, Open MPI, GPSD (C & Python), GDB, FreeRTOS, Berkeley DB, Bash, Asterisk,

VLC (много информации об архитектуре)

исходные примеры

Любой из вышеперечисленных проектов стоит прочитать. Стандартные инструменты командной строки также доступны для чтения. Ядро Linux также имеет множество проектных документов.

Ответ 11

Если вы заинтересованы в критических стандартах окружающей среды, MISRA C может вас заинтересовать. Я нашел это полезным.

Вы можете получить MISRA C 2004 здесь.

Краткий обзор обновленной MISRA C 2012 здесь.