Programming and Style Guidelines for C

E

Earl Higgins

The company where I work as a Senior Software Engineer is currently
revamping their (1991 era) "Programming and Style Guidelines", and I'm
on the committee. The company, in business for over 20 years, writes
medical software, which must ultimately pass FDA approval and ISO 9000
certification. The product the document applies to is a large system,
(just over 3 million lines of code) running on a variety of platforms
(all Unix-ish), and over 99% written in C (no C++), compiled with gcc.

There's alot wrong with the document, and there's alot of inertia in
our Engineering Department to keep committing the same mistakes we've
been doing since day one (e.g. casting return value from malloc), and
even to go so far as to mandate the use of these constructs.

I'd like to go into this project well-informed about a couple of
specific topics, and was wondering if some of the veterans of this
group could tell me whether their sympathies would lie for, or against
each of the following actual passages from the document, and why:

"C program file names must be unique within the first 14 characters.
This is a limit imposed by at least one version of UNIX where the ...
application is supported."

"Main programs should be at the start of the file. Higher level
subroutines should be below that, and the lowest level detail
functions should be at the end of the file." and "All C functions
should have function prototypes available in a header file."

"Avoid calling system commands with the "system()" or "popen()"
subroutines as they have a very high overhead."

"Each function starts with. a form feed (Control L) enclosed in a
comment so that each function starts on a new page, i.e.; /* ^L */."

Additionally, an email has been sent to the committee from the
organizing manager hinting that he favors adding the following (among
other things):

"we should explicitly ban the ternary operator"

"Please do not create structures that contain "char foo[12]" instead
create "char *foo" when the string is to be used in structure ... {and
use dynamic memory allocation instead}."

Any thoughts would be appreciated!

Earl Higgins
 
T

Thomas Matthews

Earl said:
The company where I work as a Senior Software Engineer is currently
revamping their (1991 era) "Programming and Style Guidelines", and I'm
on the committee. The company, in business for over 20 years, writes
medical software, which must ultimately pass FDA approval and ISO 9000
certification. The product the document applies to is a large system,
(just over 3 million lines of code) running on a variety of platforms
(all Unix-ish), and over 99% written in C (no C++), compiled with gcc.

There's alot wrong with the document, and there's alot of inertia in
our Engineering Department to keep committing the same mistakes we've
been doing since day one (e.g. casting return value from malloc), and
even to go so far as to mandate the use of these constructs.

I'd like to go into this project well-informed about a couple of
specific topics, and was wondering if some of the veterans of this
group could tell me whether their sympathies would lie for, or against
each of the following actual passages from the document, and why:

"C program file names must be unique within the first 14 characters.
This is a limit imposed by at least one version of UNIX where the ...
application is supported."

I prefer that the package name come first followed by the function
name: Flash_Program(), Flash_Erase(), ...

"Main programs should be at the start of the file. Higher level
subroutines should be below that, and the lowest level detail
functions should be at the end of the file." and "All C functions
should have function prototypes available in a header file."

My style is that all functions should be listed alphabetical
in the source file. The header file should list all the public
declarations, also alphabetically. I find functions easier to
find when they are listed alphabetically.

As far as the compiler and linker are concerned, the ordering
doesn't make any difference. One could argue that newer
functions be added to the top of the list; which allows the
new errors to be announced faster. Otherwise one would have
to wait for all the existing functions to be compiled before
the new errors are announced.

"Avoid calling system commands with the "system()" or "popen()"
subroutines as they have a very high overhead."

Then how are operating system functions portably executed?
One could use platform specific APIs, though.

"Each function starts with. a form feed (Control L) enclosed in a
comment so that each function starts on a new page, i.e.; /* ^L */."

This may have been relevant a long time ago when programs were
printed out. In the medical equipment company that I worked for,
we never printed out the listings; we just placed them on a
floppy and tagged it as read-only (as well as in the configuration
managment system). In my current company, source code is only
printed for code reviews; so that everybody has the same code
to review. Nobody has made any comments about functions having
to start at the tops of pages. It doesn't matter; people would
rather spend less time coding and more time partying.

Additionally, an email has been sent to the committee from the
organizing manager hinting that he favors adding the following (among
other things):

"we should explicitly ban the ternary operator"

The ternary operator can be more efficient and also can be used
in places where an "if" statement is not allowed, such as
assignments and function parameters. The ternary operator should
not be used when its meaning cannot be _simply_ read. If a
reader must take a lot of time to figure out the expression,
then some other coding technique should be used (such as an
"if" statement).

"Please do not create structures that contain "char foo[12]" instead
create "char *foo" when the string is to be used in structure ... {and
use dynamic memory allocation instead}."

In many embedded systems, dynamic allocation is evil. On the
medical products that I worked on, dynamic allocation was forbidden.
We didn't want to risk any damage caused by memory fragmentation.

The structures should use named constants instead of magic numbers.

Any thoughts would be appreciated!

Earl Higgins

In the company that I worked for, the theme was "kill the
machine, not the patient." If any exception occurred, the
machine was forced into a "safe" state. Style issues were
not as important as following the process, peforming and
documenting testing and code reviews. All revisions of
the software must be recreatable and match the executable
shipped in the product.

Have everybody in your organization read about the
"Therac 25" incident (search the web for information).

--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book
 
E

Eric Sosman

Earl said:
[... asking for comments on proposed coding standards ...]

Keep in mind that it's risky at best to evaluate procedural
standards without reference to the organization that will use
them. Coding standards are basically social contracts, and as
such can't be fully evaluated from a purely technical viewpoint.
With that as a disclaimer:
"C program file names must be unique within the first 14 characters.
This is a limit imposed by at least one version of UNIX where the ...
application is supported."

If it's true, it's true. When some target platform presents
obstacles, you must either accommodate them or drop the platform.
"Main programs should be at the start of the file. Higher level
subroutines should be below that, and the lowest level detail
functions should be at the end of the file."

It's an arbitrary choice, but not a "bad" one. Consistency
of organization can be of help to the people who read the code.
and "All C functions
should have function prototypes available in a header file."

That sounds like overkill. If it were up to me I'd say
all functions with external linkage should be so declared, but
I wouldn't insist on doing so for static functions.
"Avoid calling system commands with the "system()" or "popen()"
subroutines as they have a very high overhead."

This has quite a different character from the other quoted
standards: It doesn't actually prohibit the practice *and* it
gives a rationale. Whether the rationale is true or not depends
on what alternatives are available: It seems wasteful to examine
a directory's content by running "ls" in a sub-process, but it
seems foolish to rewrite "sendmail" from scratch.
"Each function starts with. a form feed (Control L) enclosed in a
comment so that each function starts on a new page, i.e.; /* ^L */."

No objection. It sounds like there are some automated source-
browsing or other source-consuming tools lurking in the background,
either in active or anticipated use. Markers of this sort make
good "hooks" for such tools to latch on to. My choice would have
been to just use the raw ^L without the comment delimiters, but
perhaps the tools in question have other preferences.
Additionally, an email has been sent to the committee from the
organizing manager hinting that he favors adding the following (among
other things):

"we should explicitly ban the ternary operator"

If there are statistics showing increased error rates from the
use of the ternary operator -- or of any other language feature,
for that matter -- there may be support for the "should." In the
absence of actual measurements, I personally wouldn't take so
draconian a line.
"Please do not create structures that contain "char foo[12]" instead
create "char *foo" when the string is to be used in structure ... {and
use dynamic memory allocation instead}."

This strikes me as poor advice, at least in so broad-brush a
form. Dynamic allocation carries its own headaches, and if there's
Certain Knowledge of a not-too-large upper limit on a string's
length, why not take the simpler tack? If the concern is about
buffer overflow in "general purpose" string-bashing, perhaps a
better approach might be to invent a String ADT and use it in
preference to raw char* pointers.
Any thoughts would be appreciated!

Just remember to scroll back to the top and re-read the
disclaimer, OK?
 
C

CBFalconer

Earl said:
The company where I work as a Senior Software Engineer is currently
revamping their (1991 era) "Programming and Style Guidelines", and I'm
on the committee. The company, in business for over 20 years, writes
medical software, which must ultimately pass FDA approval and ISO 9000
certification. The product the document applies to is a large system,
(just over 3 million lines of code) running on a variety of platforms
(all Unix-ish), and over 99% written in C (no C++), compiled with gcc.

There's alot wrong with the document, and there's alot of inertia in
our Engineering Department to keep committing the same mistakes we've
been doing since day one (e.g. casting return value from malloc), and
even to go so far as to mandate the use of these constructs.

I'd like to go into this project well-informed about a couple of
specific topics, and was wondering if some of the veterans of this
group could tell me whether their sympathies would lie for, or against
each of the following actual passages from the document, and why:

"C program file names must be unique within the first 14 characters.
This is a limit imposed by at least one version of UNIX where the ...
application is supported."

Agree. I would make it smaller.
"Main programs should be at the start of the file. Higher level
subroutines should be below that, and the lowest level detail
functions should be at the end of the file." and "All C functions
should have function prototypes available in a header file."

Disagree. Headers should only hold what is to be published and
exposed to external use, etc. Other functions should be marked as
"static" so the reader knows they cannot affect anything outside
the current file. Having a repetitious header unnecessarily is a
source of error, so I would attempt to reverse that order, i.e.
define everything before use, as far as possible. Avoid
"globals", and if unavoidable try to make them local to a single
file by marking as static.
"Avoid calling system commands with the "system()" or "popen()"
subroutines as they have a very high overhead."

Put the period between "commands" and "with".
"Each function starts with. a form feed (Control L) enclosed in a
comment so that each function starts on a new page, i.e.; /* ^L */."

Not useful, and may well be trouble in some compiler systems.
However I believe in a distinctive separator between functions,
and labelling the closing '}' with the function name, as in:

/* ------------------ */

/* Function overall description goes here */
int foo(char *bar)
{
/* whatever */
} /* foo */

/* ------------------ */

but guidelines as to the length of functions, and the number of
objects they handle, are useful. Look up the rule of seven.
Additionally, an email has been sent to the committee from the
organizing manager hinting that he favors adding the following
(among other things):

"we should explicitly ban the ternary operator"

Probably wise, outside of macros.
"Please do not create structures that contain "char foo[12]"
instead create "char *foo" when the string is to be used in
structure ... {and use dynamic memory allocation instead}."

Nonsense. This depends on use. Frivolous use of malloc can lead
to problems with memory fragmentation, leaks, etc. not to mention
heavy overhead.

Overall your system sounds as if it needs piecemeal improvement.
It should be possible to factor out areas, even whole files,
during maintenance. This assumes you have some sort of
performance checking software written, to ferret out silly
mistakes. With a reasonable set of policies a year or two should
make it much more managable.

I would also ban the use of // comments and of line length over 72
chars. Use of indent might be worthwhile. The following is my
indent configuration:

-kr -l66 -i3 -bad -di16 -lc66 -nce -ncs -cbi0 -bbo -pmt -psl -ts1

Get and use Cscope and cvs.
 
D

Dan Pop

In said:
I'd like to go into this project well-informed about a couple of
specific topics, and was wondering if some of the veterans of this
group could tell me whether their sympathies would lie for, or against
each of the following actual passages from the document, and why:

"C program file names must be unique within the first 14 characters.
This is a limit imposed by at least one version of UNIX where the ...
application is supported."

If it's a limit imposed by at least one supported platform, there is
nothing to argue about it, except for checking that it is still imposed
by the current version.
"Main programs should be at the start of the file. Higher level
subroutines should be below that, and the lowest level detail
functions should be at the end of the file." and "All C functions
should have function prototypes available in a header file."

If all the C functions have prototypes available in a header file that
is included, the order in which they are defined in the source code
does not matter.

Using the reverse definition order than required above (i.e. main at the
end of the file) removes the need for having prototypes for the
functions that are local to that source file.
"Avoid calling system commands with the "system()" or "popen()"
subroutines as they have a very high overhead."

These days, the overhead of system() and popen() is much less of an
issue than it was in 1991. Using them instead of forking and building
the piping by hand between the child and its parent results in much
simpler code.
"Each function starts with. a form feed (Control L) enclosed in a
comment so that each function starts on a new page, i.e.; /* ^L */."

That's a matter of pure preference.
Additionally, an email has been sent to the committee from the
organizing manager hinting that he favors adding the following (among
other things):

"we should explicitly ban the ternary operator"

I agree that, with few exceptions, the ternary operator belongs to macro
definitions only. If used with care, an absolute ban is not necessary.
"Please do not create structures that contain "char foo[12]" instead
create "char *foo" when the string is to be used in structure ... {and
use dynamic memory allocation instead}."

The right approach really depends on the purpose of the character array.

Dynamical allocation has its runtime overheads and an increased risk of
introducing hard to find bugs and memory leaks. Avoid it, when the size
of the character array can be estimated within reasonable limits when
writing the code and use it when it cannot.

Dan
 
E

E. Robert Tisdale

Earl said:
The company where I work as a Senior Software Engineer is currently
revamping their (1991 era) "Programming and Style Guidelines", and I'm
on the committee. The company, in business for over 20 years, writes
medical software, which must ultimately pass FDA approval and ISO 9000
certification. The product the document applies to is a large system,
(just over 3 million lines of code) running on a variety of platforms
(all Unix-ish), and over 99% written in C (no C++), compiled with gcc.

There's alot wrong with the document, and there's alot of inertia in
our Engineering Department to keep committing the same mistakes we've
been doing since day one (e.g. casting return value from malloc), and
even to go so far as to mandate the use of these constructs.

I'd like to go into this project well-informed about a couple of
specific topics, and was wondering if some of the veterans of this
group could tell me whether their sympathies would lie for, or against
each of the following actual passages from the document, and why:

"C program file names must be unique within the first 14 characters.
This is a limit imposed by at least one version of UNIX
where the ... application is supported."

Can you identify which version of UNIX imposes this limit?
"Main programs should be at the start of the file.
Higher level subroutines should be below that and
the lowest level detail functions should be at the end of the file."

I believe that the C compiler needs to see the *definition*
of a function before it can 'inline' it.
and "All C functions should have function available in a header file."

No.
Private function declarations should be restricted to the scope
of the implementation file which invokes them
and should be defined as 'static' functions whenever possible.
"Each function starts with. a form feed (Control L) enclosed in a
comment so that each function starts on a new page, i.e.; /* ^L */."

I don't know of any viable C compiler
that doesn't treat a formfeed ^L as a whitespace.
Use them to divide your program listing up into readable pages.
You should be able to get more than one function on a page.
If you need to insert formfeeds in the body of a function,
then the function is probably too long and needs to be factored.
Additionally,
an email has been sent to the committee from the organizing manager
hinting that he favors adding the following (among other things):


"we should explicitly ban the ternary operator"

Nonsense!
The ternary operator is essential in variable and constant definitions:

const int i = (1 < argc)? atoi(argv[1]): 0;
"Please do not create structures that contain "char foo[12]"
instead create "char *foo" when the string is to be used in structure
{and use dynamic memory allocation instead}."

Nonsense! Small arrays of static size
should *not* be allocated from the free store.
 
A

Alexander Bartolich

begin followup to Earl Higgins:
[...] Any thoughts would be appreciated!

Any rule that is not checked by reality, machinery or a motivated
quality control department is worthless. Unless you have an effective
review process this red tape is meaningless.

From my experience the most common "style" problems are:

1. Programming by copy-and-paste.

Programmer needs existing functionality in a slightly different
way, copies existing code, replaces critical parts by hand.
Maximum productivity, congratulations by management.

2. Programming by if-cascade.

Programmer needs existing functionality in a slightly different
way, introduces another global variable (another class member,
another environment variable, another hash table entry, etc.),
replaces hopefully all critical parts by an if-statement.
High productivity, congratulations by management.

3. Programming by master-slave (also called top-down).

The Right Solution (TM) to items 1. and 2. is to redesign the
interface, code, algorithm, data-structure, etc. But then the
wish to redesign comes from a coding-slave, and the design
was made by the expert manager. Criticism is mutinity.

None of these problems has anything to do with the use of a?b:c,
multiple exit points per function, or even evil incarnate, goto.
 
J

Johan Lindh

Alexander said:
begin followup to Earl Higgins:
[...] Any thoughts would be appreciated!


Any rule that is not checked by reality, machinery or a motivated
quality control department is worthless. Unless you have an effective
review process this red tape is meaningless.

From my experience the most common "style" problems are:

1. Programming by copy-and-paste.

Programmer needs existing functionality in a slightly different
way, copies existing code, replaces critical parts by hand.
Maximum productivity, congratulations by management.

2. Programming by if-cascade.

Programmer needs existing functionality in a slightly different
way, introduces another global variable (another class member,
another environment variable, another hash table entry, etc.),
replaces hopefully all critical parts by an if-statement.
High productivity, congratulations by management.

3. Programming by master-slave (also called top-down).

The Right Solution (TM) to items 1. and 2. is to redesign the
interface, code, algorithm, data-structure, etc. But then the
wish to redesign comes from a coding-slave, and the design
was made by the expert manager. Criticism is mutinity.

None of these problems has anything to do with the use of a?b:c,
multiple exit points per function, or even evil incarnate, goto.

If this had been /., I'd have moderated +1, Insightful.

/J
 
E

Ed Morton

Earl Higgins wrote:

"C program file names must be unique within the first 14 characters.
This is a limit imposed by at least one version of UNIX where the ...
application is supported."

I ran into this on Ahmdahl and VAX mainframes several years ago. The
file names had to be restricted to 12 characters rather than 14, though,
because the change management system that was used added a 2-char suffix
to files that you took "out for edit" so your 12-char source file name
became a 14-char editable file name.
"Main programs should be at the start of the file. Higher level
subroutines should be below that, and the lowest level detail
functions should be at the end of the file."

I find the opposite order easier to read, but any order is fine.
Alphabetical is as good as any.

and "All C functions
should have function prototypes available in a header file."

Yes. The more interesting question is how you pick an apporopriate
header file based on its visibility wrt however your source files are
organized.
"Avoid calling system commands with the "system()" or "popen()"
subroutines as they have a very high overhead."

I doubt if anyone would call system() unless they NEED to, so this
restriction seems a bit pointless.
"Each function starts with. a form feed (Control L) enclosed in a
comment so that each function starts on a new page, i.e.; /* ^L */."

Handy on raw text printouts, but there's plenty of tools around that can
do pretty printing of code.

Something else you might consider is generally only having one function
per file. If you're in an environment where multiple people are changing
code in the same functional area simultaneously, having separate files
can help reduce collision problems.
Additionally, an email has been sent to the committee from the
organizing manager hinting that he favors adding the following (among
other things):

"we should explicitly ban the ternary operator"

Don't do that. I've seen the rule be "only use the ternary operator in a
macro" but I'd see this as more of a general guidline than a solid rule.
"Please do not create structures that contain "char foo[12]" instead
create "char *foo" when the string is to be used in structure ... {and
use dynamic memory allocation instead}."

No, just use each approriately. In the first case, though, I would use a
#define'd value instead of a hard-coded "12" for foo's range.

Ed.
 
D

Default User

Ed said:
Earl Higgins wrote:

I doubt if anyone would call system() unless they NEED to, so this
restriction seems a bit pointless.


You might be surprised. It's more of a problem with programming in
POSIX, because there are a lot of library calls that are similar to
shell commands. For instance, using system() to call the chmod shell
command, because the programmer isn't familiar with the library version
of it.

Even for ISO standard use, I've seen people do a system("rm somefile")
because they didn't know about the remove() function.



Brian Rodenborn
 
C

CBFalconer

E. Robert Tisdale said:
Earl said:
The company where I work as a Senior Software Engineer is currently
revamping their (1991 era) "Programming and Style Guidelines", and I'm
on the committee. The company, in business for over 20 years, writes
medical software, which must ultimately pass FDA approval and ISO 9000
certification. The product the document applies to is a large system,
(just over 3 million lines of code) running on a variety of platforms
(all Unix-ish), and over 99% written in C (no C++), compiled with gcc.

There's alot wrong with the document, and there's alot of inertia in
our Engineering Department to keep committing the same mistakes we've
been doing since day one (e.g. casting return value from malloc), and
even to go so far as to mandate the use of these constructs.

I'd like to go into this project well-informed about a couple of
specific topics, and was wondering if some of the veterans of this
group could tell me whether their sympathies would lie for, or against
each of the following actual passages from the document, and why:

"C program file names must be unique within the first 14 characters.
This is a limit imposed by at least one version of UNIX
where the ... application is supported."

Can you identify which version of UNIX imposes this limit?
"Main programs should be at the start of the file.
Higher level subroutines should be below that and
the lowest level detail functions should be at the end of the file."

I believe that the C compiler needs to see the *definition*
of a function before it can 'inline' it.
and "All C functions should have function available in a header file."

No.
Private function declarations should be restricted to the scope
of the implementation file which invokes them
and should be defined as 'static' functions whenever possible.
"Each function starts with. a form feed (Control L) enclosed in a
comment so that each function starts on a new page, i.e.; /* ^L */."

I don't know of any viable C compiler
that doesn't treat a formfeed ^L as a whitespace.
Use them to divide your program listing up into readable pages.
You should be able to get more than one function on a page.
If you need to insert formfeeds in the body of a function,
then the function is probably too long and needs to be factored.
Additionally,
an email has been sent to the committee from the organizing manager
hinting that he favors adding the following (among other things):


"we should explicitly ban the ternary operator"

Nonsense!
The ternary operator is essential in variable and constant definitions:

const int i = (1 < argc)? atoi(argv[1]): 0;
"Please do not create structures that contain "char foo[12]"
instead create "char *foo" when the string is to be used in structure
{and use dynamic memory allocation instead}."

Nonsense! Small arrays of static size
should *not* be allocated from the free store.

Congratulations! Apart from the first two and the last two
comments, you actually make sense in this article.
 
J

J. J. Farrell

"C program file names must be unique within the first 14 characters.
This is a limit imposed by at least one version of UNIX where the ...
application is supported."

If the rationale is still correct, the rule makes obvious sense.
If not, is there any real point in changing it and having newer
stuff different from older stuff?
"Main programs should be at the start of the file. Higher level
subroutines should be below that, and the lowest level detail
functions should be at the end of the file." and "All C functions
should have function prototypes available in a header file."

There are arguments in various directions in this area, but none
of them are particularly strong. I don't personally like putting
things in headers that don't need to be there. Consistency is more
important than anything else in this area, so I'd leave it be.
"Avoid calling system commands with the "system()" or "popen()"
subroutines as they have a very high overhead."

This needs reverse engineering to work out what it's really trying
to say, analysing to see if it's still true, then re-writing if
appropriate. At the moment it says that I should write my own
implementation of system() when I want to execute a separate
program. That's nonsense. It probably means to tell me to avoid
executing other programs. That may make sense, but needs quantifying.
It would be crazy to write thousands of lines of code that get
used once in a blue moon when a single call to system() would do.
"Each function starts with. a form feed (Control L) enclosed in a
comment so that each function starts on a new page, i.e.; /* ^L */."

Probably no longer useful, but no big deal. Again, think
"consistency". Why change a style that has little overhead and
everyone is used to, for negligible benefit, resulting in new
code looking different from old code.
Additionally, an email has been sent to the committee from the
organizing manager hinting that he favors adding the following (among
other things):

"we should explicitly ban the ternary operator"

Why? Without some rationale, this seems plain silly.
"Please do not create structures that contain "char foo[12]" instead
create "char *foo" when the string is to be used in structure ... {and
use dynamic memory allocation instead}."

Again, why? This seems actively harmful rather than silly. It
adds run-time complexity, inefficiency, lots of potential for
bugs, and complexity in debugging, for no benefit whatsoever
that I can see.

Perhaps it's time to suggest that the manager get on with
managing and leave C issues to C programmers. This reminds
me of the Dilbert episode with PHB saying "Why don't you try
pressing that button there".
 
N

Nick Landsberg

J. J. Farrell wrote:

[Much snipped]
Perhaps it's time to suggest that the manager get on with
managing and leave C issues to C programmers. This reminds
me of the Dilbert episode with PHB saying "Why don't you try
pressing that button there".

Over the years, I have found managers to be like the
cat that Mark Twain once described. Something along
the lines of "if a cat were to sit on a hot stove lid,
that cat would never sit on a hot stove lid again. Nor
would it ever sit on a cold stove lid."

Stove lids are things of antiquity, now, but the
behavior remains. Once burned twice shy, so they
try to mandate others' behavior.

We had a problem once, over 20 years ago, where the
cause was traced to a "makefile" not properly
referencing the dependency on a nested include.
Management's reaction was to ban all nested includes.

On another project, there were so many memory leaks
that the management mandated that the use of malloc()
was banned. I will leave it as an exercise to the reader
to imagine what happened when they had to deliver to
a really large customer with large lists of "things" but
small savvy customers complained about the memory usage.
 
J

Jack Klein

The company where I work as a Senior Software Engineer is currently
revamping their (1991 era) "Programming and Style Guidelines", and I'm
on the committee. The company, in business for over 20 years, writes
medical software, which must ultimately pass FDA approval and ISO 9000
certification. The product the document applies to is a large system,
(just over 3 million lines of code) running on a variety of platforms
(all Unix-ish), and over 99% written in C (no C++), compiled with gcc.

So you're in a medical environment where you must deal with FDA's GMP.
To a great extent it depends on the category your product falls into
under the hazard analysis. It sounds like you have some kind of
diagnostic, imaging, or analysis software package that might possibly
cause misdiagnosis on error, but does not directly have the chance to
cause injury, such as controlling the radiation exposure or the motor
moving the patient relative to the equipment.

For C, start with this book which every C programmer should read:

Safer C: Developing Software in High-integrity and Safety-critical
Systems
Les Hatton
McGraw-Hill Education - Europe; ISBN: 0077076400

Despite the title, every professional C programmer should read this
book.

It is difficult to find this book in the US. It can be ordered from
sources like amazon.co.uk (I don't know if they ship to the US), or
from Blackwell's who do ship to the US, although it took a month for
my copy to arrive.

The next place to go is http://www.misra.org.uk and get a copy of the
Misra C Guidelines. Version 2 won't be out until sometime in the
second quarter, but buy the original version now and the new one when
it becomes available. It is inexpensive enough.

Misra has some very excellent rules and some very poor ones, and it is
unlikely that any two experienced programmers will agree on which are
which. It leans towards rules relevant for small embedded systems.
Nevertheless it is the first serious attempt to put together a set of
rules for systems that must be highly reliable. It is largely based
on Hatton's work, and Andrew Koenig's "C Traps and Pitfalls", another
excellent source.

Then get Gimpel lint (PC-Lint or their UNIX flavor). It has a rule
set for MISRA C included. It takes some effort to tune it properly
for your code, but the payoff is enormous. If one of your platforms
is a PC, or your code base can at least build on a Windows PC, PC-Lint
is a real bargain.
There's alot wrong with the document, and there's alot of inertia in
our Engineering Department to keep committing the same mistakes we've
been doing since day one (e.g. casting return value from malloc), and
even to go so far as to mandate the use of these constructs.

I'd like to go into this project well-informed about a couple of
specific topics, and was wondering if some of the veterans of this
group could tell me whether their sympathies would lie for, or against
each of the following actual passages from the document, and why:

"C program file names must be unique within the first 14 characters.
This is a limit imposed by at least one version of UNIX where the ...
application is supported."

Is it the OS, or perhaps an auxiliary tool like the version control
system or make utility? If the latter, those can be replaced. It
sounds suspiciously like this might be the case, since the requirement
is "unique within the first 14 characters", rather than cannot have
more than 14 characters.
"Main programs should be at the start of the file. Higher level
subroutines should be below that, and the lowest level detail
functions should be at the end of the file." and "All C functions
should have function prototypes available in a header file."

The first is pretty much a pure style rule. The second is far more
important. Whenever possible, functions should be defined with the
static keyword for internal linkage. In that case, the prototypes for
all static functions must be at the top of the source file. All
functions with external linkage must have a prototype in a header
file. That header file must be included in the source file defining
the function as well as any other source files calling it. Function
prototypes are not allowed in source files unless they functions are
static.

In my company (medical equipment, possibility of direct injury as well
as misdiagnosis), where the current coding standards are largely my
doing, the extern keyword is not allowed to appear in a C source file.
They must have declarations in a header file, and like function
prototypes, the source code defining the external object must include
the header as well as other source files that reference it.
"Avoid calling system commands with the "system()" or "popen()"
subroutines as they have a very high overhead."

This is a pretty meaningless statement. How many runtime functions do
you use that indirectly make system calls anyway?
"Each function starts with. a form feed (Control L) enclosed in a
comment so that each function starts on a new page, i.e.; /* ^L */."

I thought this went away with dot-matrix printers, fan-fold paper, and
the 1980s. Still, the form feed character, Control L in ASCII, is
part of the basic source character set, so all conforming compilers
can deal with it.

I find this one pretty useless. Far, far better to use something like
Doxygen to generate readable documentation than this.
Additionally, an email has been sent to the committee from the
organizing manager hinting that he favors adding the following (among
other things):

"we should explicitly ban the ternary operator"

I disagree with this one, although it can be abused and some
programmers will never grasp the distinction between appropriate and
inappropriate use. Chained ternary operators should be absolutely
forbidden.
"Please do not create structures that contain "char foo[12]" instead
create "char *foo" when the string is to be used in structure ... {and
use dynamic memory allocation instead}."

In truly high reliability systems, dynamic memory allocation is not
allowed at all. Using dynamic memory for small blocks can be very
troublesome, since large memory fragmentation can result. Of course
desktop/workstation applications can always be shut down and
restarted, and the box rebooted if necessary (especially if it on
Windows). Systems that absolutely must function 24/7 without shutdown
or reboot really can't afford dynamic memory at all.

And if those structures need to be copied, you run into all the issues
of shallow vs. deep copy and the possibility of the same pointer
getting freed twice.
 
P

pete

Earl said:
"All C functions
should have function prototypes available in a header file."

Static functions should only have their prototypes
in the same C file as their defintitions.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,060
Latest member
BuyKetozenseACV

Latest Threads

Top