Coding Standards for pure C (not C++)

杀马特。学长 韩版系。学妹 提交于 2019-12-29 11:00:12

问题


I come from a java background (from my CS classes) and a semester of C++. I am just finishing up a OpenCV project for my Co-Op that's in pure C, so I'm a bit late in asking this question.

What are the design processes and coding standards for pure C?

I'm familiar with object oriented programming, design and best practices. I'm just a bit at a loss at a non-object oriented language like C. Every single variable and function appears to be global. It makes it feel like a real mess to me.


回答1:


You may be interested in checking out the answers to a similar question I asked not too long ago. Moreover, if you're interested in C style guides, you may want to take a look at this page since it is a repository for C (and C++) style guides. If you're in the mood for a good laugh, please take a look at the NASA C Style Guide. In particular, take a look at the massive comment... you'll know which one I'm talking about. Don't write comments like this please.

I personally recommend the Indian Hill C Style Guide with some modifications. Furthermore, you may want to purchase the book C Interfaces and Implementations if you're having trouble designing large-scale programs in C.




回答2:


I honestly don't think that any number of answers on StackOverflow are going to teach you how to design and write well-structured C programs. You need to read a good book, and the obvious one to read is The C Programming Language by Kernighan & Ritchie.




回答3:


I have no professionnal experience on C (only on C++), so don't take my advices, tricks and tips too seriously, as they are "object-like-oriented".

Almost Object C?

Simulating basic object-like features can be done easily:

In the header, forward declare your type, typedef it, and declare the "methods". For example:

/* 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) ;

You'll see each functions is prefixed. I choose the name of the "struct" to make sure there won't be collision with another code.

You'll see, too, that I used "p_pThis" to keep with the OO-like idea.

In the source file, define your type, and define the functions:

/* 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. */

If you want "private" functions (or private global variables), declare them static in the C source. This way, they won't be visible outside:

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

static int g_iMyPrivateCounter = 0 ;

If you want inheritance, then you're almost screwed. If you believed everything in C was global, including variable, then you should get more experience in C before even trying to think how inheritance could be simulated.

Misc. Tips

Avoid multiple code-paths.

For example, multiple returns is risky. For example:

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

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

   free(p) ;
}

Avoid non-const globals

This include "static" variables (which are not static functions).

Global non-const variables are almost always a bad idea (i.e. see C API strtok for an example of crappy function), and if producing multithread safe code, they are a pain to handle.

Avoid name collision

Choose a "namespace" for your functions, and for your defines. This could be:

#define GROOVY_LIB_x_MY_CONST_INT 42

void GroovyLib_dosomething() ;

Beware defines

Defines can't be avoided in C, but they can have side effects!

#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 !!! */
}

Initialize your variables

Avoid declaring variables without initializing them:

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 ! */

Uninitialized variables are causes of painful bugs.

Know all the C API

The C API function list as described in the K&R is quite small. You'll read the whole list in 20 minutes. You must know those functions.

Wanna some experience?

Rewrite the C API. For example, try to write your own version of the string.h functions, to see how it is done.




回答4:


You can make a function or object's scope local to its source file by declaring it "static". That helps a bit.

Otherwise, the typical idiom I see for avoiding namespace clashes is to put some kind of facility identifier onto the name. For instance, everything in foo.c might be named foo_*




回答5:


Work with other good C programmers. Have a code review with them. Not only let them look at your code, but you look at their code.




回答6:


Good news is that you can program in a semi-object oriented fashion in C. You can protect data, expose access functions, etc. It may not have all of the fanciness of C++, but from what I have seen of other people's C++ code, many people do not use the fanciness anyway. In other words, people write C code inside a class, where in C you'd write the same code without the class container.

First, read a book on C programming and style, K&R is fine. Second, I'd recommend checking out CERT Programming Standard. Even though this site is primarily focused on "Secure" coding standards, much of the content here is general code quality standards everyone should follow. Doing the things mentioned here will improved your quality, eliminate pesky bugs, and as a side effect, make your code more secure.




回答7:


You may want to have a good look at the source of The Linux Kernel..... BTW it is not the easiest piece of code to start with but since you are from a programming background, it may help... As an object-oriented programmer, you might particularly find error-handling in C an uphill task. May be this helps---> http://www.freetype.org/david/reliable-c.html




回答8:


You can do object oriented design in pure C. An easy approach is to think of a module as a class with public methods as ordinary functions that require the this parameter as an explicit first argument.

It helps if the class name is a prefix on the function name, and if all private functions and class data are declared static. You build constructors with malloc() to get the memory, and explicit initialization of the data fields.

A constructor for an object with entirely private data members can expose an opaque pointer (typed void * even, or as a pointer to an incomplete type if type safety is desired). If you want to have only public data members, then a pointer to a publicly defined struct works well.

This pattern is followed by a number of libraries. An initialization function returns a cookie that must be passed back to all library methods, and one method serves as a destructor.

Of course, there are other ways to design well in pure C, but if OO works for you, you don't have to abandon it completely.




回答9:


You can restrict visibility of file-scope variables and functions to their respective source files (although that doesn't prevent you from passing pointers to these objects around).

For example:

/** 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:


Coding Style

systemd

systemd code quality tools

RIOT-OS

nginx

Git Source Guidelines

FFmpeg

curl

Architecture

The Architecture of Open Source Applications C programs there include Git, Nginx, Open MPI, GPSD (C & Python), GDB, FreeRTOS, Berkeley DB, Bash, Asterisk,

VLC (lots of architecture info)

source examples

Any of the above projects are worth a read. Standard command-line tools are also available to read. The Linux kernel has a lot of design documents out there too.




回答11:


If you are interested in critical environment standards, then MISRA C could be of interest to you. I found it helpful.

You can get MISRA C 2004 here.

Short overview of the updated MISRA C 2012 here.



来源:https://stackoverflow.com/questions/1262459/coding-standards-for-pure-c-not-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!