Misra C 2004
Misra C 2004
Misra C 2004
MISRA-C:2004
Guidelines
for the use
of the
C language
in critical
systems
October 2004
Licensed to: Siemans VDO Automotive AG
8 Feb 2005, up to 1000 users.
MISRA and the triangle logo are registered trademarks of MIRA Limited, held on behalf of the
MISRA Consortium.
All rights reserved. No part of this publication may be reproduced, stored in a retrieval system or
transmitted in any form or by any means, electronic, mechanical or photocopying, recording or otherwise
without the prior written permission of the Publisher.
MISRA-C:2004
Guidelines
for the use
of the
C language
in critical
systems
October 2004
i
MISRA Mission Statement: To provide assistance to the automotive industry in the application and
creation within vehicle systems of safe and reliable software.
MISRA, The Motor Industry Software Reliability Association, is a collaboration between vehicle
manufacturers, component suppliers and engineering consultancies which seeks to promote best practice
in developing safety-related electronic systems in road vehicles and other embedded systems. To this end
MISRA publishes documents that provide accessible information for engineers and management, and
holds events to permit the exchange of experiences between practitioners.
www.misra.org.uk
Disclaimer
Adherence to the requirements of this document does not in itself ensure error-free robust software or
guarantee portability and re-use.
Compliance with the requirements of this document, or any other standard, does not of itself confer
immunity from legal obligations.
ii
Foreword
In preparing the original MISRA-C:1998 [1] document, it was hoped to make some impact in the use of
software within the UK automotive industry. Since 1998, the successes and global use of
MISRA-C:1998 across automotive, aerospace, medical and other industries has been staggering.
Since the publication of MISRA-C:1998, we have received considerable comment on the good, bad, and
in some cases impractical rules included. We therefore set about the task of producing an update,
MISRA-C:2004 (this document), which improves on, and corrects the issues faced by software engineers
implementing MISRA-C:1998.
While producing MISRA-C:2004, the question of addressing the 1999 C standard [8] arose. At this time,
only issues with MISRA-C:1998 are addressed due to the limited support for C99 on embedded
microprocessors.
For the last few years, a dedicated group have met, representing a broad range of interests to refine and
produce MISRA-C:2004. I would like to thank this team for their effort and support.
I would also like to recognise our global partners who have aided our global preparation of
MISRA-C:2004. In the USA, this has been with the SAE J2632 committee led by Bruce Emaus. In Japan,
we have worked with representatives of JSAE, JAMA, and the MISRA-C Study Group, and I would
particularly like to thank Takao Futagami for his role in co-ordinating access to these groups.
I would also like to thank all those in a wider group who have provided comments and support to the
MISRA-C effort. This includes all those who participated in the review during 2003, which led to some
rules being re-designed to address the comments received.
In presenting MISRA-C:2004, we have attempted to refine the document in a number of ways.
We have introduced rules for arithmetic operations which provide a sound base for simple and
robust statements.
The MISRA-C project remains on-going, and this document will be subsequently supported by a
compliance suite at www.misra-c.com to provide definitive code to test tool compliance.
This document specifies a subset of the C programming language which is intended to be suitable for
embedded systems. It contains a list of rules concerning the use of the C programming language
together with justifications and examples.
iii
Acknowledgements
The MISRA consortium would like to thank the following individuals for their significant contribution
to the writing of this document:
Paul Burden
Andrew Burnard
Mike Hennell
Chris Hills
Gavin McCall
Steve Montgomery
Chris Tapp
Liz Whiting
The MISRA consortium also wishes to acknowledge contributions from the following individuals during the development and review process:
Ganapti Avadhani
Walter Banks
David Blyth
Paul Boultwood
Richard Burke
Ian Chalinder
Kwok Chan
Paul Clark
Valery Creux
David Crocker
William Derouchie
Alain Deutsch
Todd Dowty
Manoj Dwivedi
Mike Ellims
Bruce Emaus
Andy Fiore
William Forbes
S.W. Freeman
Takao Futagami
Robert Galles
Jon Garnsworthy
James F. Gimpel
Martin Gray
Robert Gruszczynski
Rob Hague
Trenton Haines
Takahiro Hashimoto
Les Hatton
Manabu Hirozawa
Hartmut Hrner
Motozo Ikeda
Yoshikazu Imura
Dern Jrme
Bernd Jesse
Stuart Jobbins
Derek Jones
Jeff Kanoza
Shigeyuki Kawana
Roland Kilgore
Helmar Kuder
Koyo Kuroda
Tom Lake
Lars Magnusson
Patrick Markl
Martin Meyer
Claude Mignen
Andrew Mijat
Svante Mller
Olwen Morgan
Stephen D. Morton
Tadanori Nakagawa
Heather Neil
Jacob Nevins
Michael Niemetz
Yuji Ninagawa
Kenji Ohgoshi
Satoru Ohtsuka
Greg Palarski
Stephen Parker
Richard Parkins
Patrik Persson
Bernd Reh
Chris Sampson
Dana Sawyer
Walter Schilling
Kotaro Seike
Yoko Sekimoto
Raul Selgado
Darren Sexton
Norman S. Shelvik
Joao Silva
Jochem Spohr
Geert Starre
Richard Swanton
Benjamin Sweet
Musubi Uno
Yan Wang
David Ward
Michael Warmuth
Thomas Wengler
Paul Whiston
Karl Woelfer
David Wright
Shoji Yamashita
The contributions of Society of Automotive Engineering (SAE) Embedded Software Taskforce, Japanese
Society of Automotive Engineers (JSAE), Japanese Automotive Manufacturers Association (JAMA) and
Herstellerinitiative Software (HIS) Working Group (Arbeitskreis) Software Test are acknowledged.
iv
Contents
1.
1
1
1
3
4
2.
5
5
5
3.
6
6
6
6
7
7
7
4.
5.
16
16
16
16
17
18
20
6.
Rules ........................................................................................................................................
6.1 Environment ...................................................................................................................
6.2 Language extensions ......................................................................................................
6.3 Documentation ................................................................................................................
6.4 Character sets .................................................................................................................
6.5 Identifiers .......................................................................................................................
6.6 Types ..............................................................................................................................
6.7 Constants ........................................................................................................................
6.8 Declarations and definitions ...........................................................................................
6.9 Initialisation ....................................................................................................................
6.10 Arithmetic type conversions ...........................................................................................
6.11 Pointer type conversions .................................................................................................
21
21
22
23
25
26
29
30
31
33
35
47
Contents (continued)
6.12
6.13
6.14
6.15
6.16
6.17
6.18
6.19
6.20
6.21
Expressions ...................................................................................................................
Control statement expressions .......................................................................................
Control flow ..................................................................................................................
Switch statements ..........................................................................................................
Functions .......................................................................................................................
Pointers and arrays ........................................................................................................
Structures and unions ....................................................................................................
Preprocessing directives ................................................................................................
Standard libraries ..........................................................................................................
Run-time failures .........................................................................................................
48
56
60
63
66
68
71
75
81
85
References ...............................................................................................................................
87
89
98
7.
vi
1. Background
1. Background The use of C and issues with it
1.1 The use of C in the automotive industry
MISRA-C:1998 [1] was published in 1998. This document is a revision to that document to address the
issues identified with that first version.
The C programming language [2] is growing in importance and use for real-time embedded applications
within the automotive industry. This is due largely to the inherent language flexibility, the extent of
support and its potential for portability across a wide range of hardware. Specific reasons for its use
include:
For many of the microprocessors in use, if there is any other language available besides
assembly language then it is usually C. In many cases other languages are simply not
available for the hardware.
C gives good support for the high-speed, low-level, input/output operations, which are
essential to many automotive embedded systems.
Increased complexity of applications makes the use of a high-level language more appropriate
than assembly language.
C can generate smaller and less RAM-intensive code than many other high-level languages.
1. Background (continued)
Firstly, in terms of style and expressiveness C can be used to write well laid out, structured and
expressive code. It can also be used to write perverse and extremely hard-to-understand code. Clearly
the latter is not acceptable in a safety-related system.
Secondly the syntax of C is such that it is relatively easy to make typing mistakes that lead to perfectly
valid code. For example, it is all too easy to type = (assignment) instead of == (logical comparison)
and the result is nearly always valid (but wrong), while an extra semi-colon on the end of an if statement
can completely change the logic of the code.
Thirdly the philosophy of C is to assume that the programmers know what they are doing, which can
mean that if errors are made they are allowed to pass unnoticed by the language. An area in which C is
particularly weak in this respect is that of type checking. C will not object, for example, if the
programmer tries to store a floating-point number in an integer that they are using to represent a
true/false value. Most such mismatches are simply forced to become compatible. If C is presented with
a square peg and a round hole it doesnt complain, but makes them fit!
1.2.2 The programmer misunderstands the language
Programmers can misunderstand the effect of constructs in a language. Some languages are more open
to such misunderstandings than others.
There are quite a number of areas of the C language that are easily misunderstood by programmers. An
example is the set of rules for operator precedence. These rules are well defined, but very complicated,
and it is easy to make the wrong assumptions about the precedence that the operators will take in a
particular expression.
1.2.3 The compiler doesnt do what the programmer expects
If a language has features that are not completely defined, or are ambiguous, then a programmer can
assume one thing about the meaning of a construct, while the compiler can interpret it quite differently.
There are many areas of the C language which are not completely defined, and so behaviour may vary
from one compiler to another. In some cases the behaviour can vary even within a single compiler,
depending on the context. Altogether the C standard, in Annex G, lists 201 issues that may vary in this
way. This can present a sizeable problem with the language, particularly when it comes to portability
between compilers. However, in its favour, the C standard [2] does at least list the issues, so they are
known.
1. Background (continued)
1.2.4 The compiler contains errors
A language compiler (and associated linker etc.) is itself a software tool. Compilers may not always
compile code correctly. They may, for example, not comply with the language standard in certain
situations, or they may simply contain bugs.
Because there are aspects of the C language that are hard to understand, compiler writers have been
known to misinterpret the standard and implement it incorrectly. Some areas of the language are more
prone to this than others. In addition, compiler writers sometimes consciously choose to vary from the
standard.
1.2.5 Run-time errors
A somewhat different language issue arises with code that has compiled correctly, but for reasons of the
particular data supplied to it causes errors in the running of the code. Languages can build run-time
checks into the executable code to detect many such errors and take appropriate action.
C is generally poor in providing run-time checking. This is one of the reasons why the code generated
by C tends to be small and efficient, but there is a price to pay in terms of detecting errors during
execution. C compilers generally do not provide run-time checking for such common problems as
arithmetic exceptions (e.g. divide by zero), overflow, validity of addresses for pointers, or array bound
errors.
1. Background (continued)
1.4 C standardization
The standard used for this document is the C programming language as defined by ISO 9899:1990 [2],
amended and corrected by ISO/IEC 9899/COR1:1995 [4], ISO/IEC 9899/AMD1:1995 [5], and ISO/IEC
9899/COR2:1996 [6]. For convenience, this is referred to as C90 in this document. The base 1990
document [7] is the ISO version of ANSI X3.159-1989 [2]. In content the ISO/IEC standard and the
ANSI standard are identical. Note, however, that the section numbering is different in the two standards,
and this document follows the section numbering of the ISO standard.
Also note that the ANSI standard [7] contains a useful appendix giving the rationale behind some of the
decisions made by the standardization committee. This appendix does not appear in the ISO edition.
This working group has considered ISO/IEC 9899:1999 [8] (known as C99). At the time of
publication (October 2004), no commercial embedded C99 compilers were available.
2. The Vision
2. MISRA-C: The vision
2.1 Rationale for the production of MISRA-C
The MISRA consortium published its Development Guidelines for Vehicle Based Software [9] in
1994, which describes the full set of measures that should be used in software development. In
particular, the choices of language, compiler and language features to be used, in relationship with
safety integrity level, are recognised to be of major importance. Section 3.2.4.3 (b) and Table 3 of the
MISRA Guidelines [9] address this. One of the measures recommended is the use of a subset of a
standardized language, which is already established practice in the aerospace, nuclear and defence
industries. This document addresses the definition of a suitable subset of C.
3. Scope
3. MISRA-C: Scope
3.1 Base languages issues
The MISRA Guidelines [9] (Table 3) requires that a restricted subset of a standardized structured
language be used. For C, this means that the language must only be used as defined in the ISO
standard. This therefore precludes the use of:
K&R C (as defined in the First Edition of The C Programming language by Kernighan and
Ritchie)
C++
3.3 Applicability
This document is designed to be applied to production code in automotive embedded systems.
In terms of the execution environments defined by ISO 9899 [2] (section 5.1.2), this document is aimed
at a free-standing environment, although it also addresses library issues since some standard libraries
will often be supplied with an embedded compiler.
Most of the requirements of this document may be applicable to embedded systems in other sectors if
such use is considered appropriate. The requirements of this document will not necessarily be
applicable to hosted systems.
It is also not necessary to apply the rules in full when performing compiler and static tool
benchmarking. Sometimes it will be necessary to deliberately break the rules when benchmarking tools,
so as to measure the tools responses.
3. Scope (continued)
3.4 Prerequisite knowledge
This document is not intended to be an introduction or training aid to the subjects it embraces. It is
assumed that readers of this document are familiar with the ISO C programming language standard and
associated tools, and also have access to the primary reference documents. It also assumes that users
have received appropriate training and are competent C language programmers.
4. Using MISRA-C
4. Using MISRA-C
4.1 The software engineering context
Using a programming language to produce source code is just one activity in the software development
process. Adhering to best practice in this one activity is of very limited value if the other commonly
accepted development issues are not addressed. This is especially true for the production of
safety-related systems. These issues are all addressed in the MISRA Guidelines [9] and, for example,
include:
Project management
Configuration management
Hazard analysis
Requirements
Design
Coding
Verification
Validation
It is necessary for the software developers to justify that the whole of their development process is
appropriate for the type of system they are developing. This justification will be incomplete unless a
hazard analysis activity has been performed to determine the safety integrity level of the system.
Training
Style guide
Metrics
Test coverage
The use of the C programming language for high-integrity and safety-related systems
The use of static checking tools used to enforce adherence to the subset
statement complexity
naming conventions
inclusion of company name, copyright notice and other standard file header information
While some of the content of the style guide may only be advisory, some may be mandatory. However
the enforcement of the style guide is outside the scope of this document.
For further information on style guides see [14].
4.2.3 Tool selection and validation
When choosing a compiler (which should be understood to include the linker), an ISO C compliant
compiler should be used whenever possible. Where the use of the language is reliant on an
implementation-defined feature (as identified in Annex G.3 of the ISO standard [2]) then the
developer must benchmark the compiler to establish that the implementation is as documented by the
compiler writer. See section 5.5.2 for more explanation of Annex G.
The size of the existing user base together with an inspection of the faults reported over the previous 6
to 12 months will give an indication of the stability of the tool.
It is often not possible to obtain this level of assurance from tool suppliers, and in these cases the onus
is on the developer to ensure that the tools are of adequate quality.
Some possible approaches the developer could adopt to gain confidence in the tools are:
The validation test could be performed by creating code examples to exercise the tools. For compilers
this could consist of known good code from a previous application. For a static checking tool, a set of
code files should be written, each breaking one rule in the subset and together covering as many as
possible of the rules. For each test file the static checking tool should then find the non-conformant code.
Although such tests would necessarily be limited they would establish a basic level of tool performance.
It should be noted that validation testing of the compiler must be performed for the same set of
compiler options, linker options and source library versions used when compiling the product code.
10
code size
cyclomatic complexity
With a planned approach, the extra effort expended on software design, language use and design for test
is more than offset by the reduction in the time required to achieve high statement coverage during test.
See [16, 17].
11
Rule No.
1.1
1.2
1.3
1.4
1.5
Manual Review
Proc x.y
12
Specific Deviation: A Specific Deviation will be defined for a specific instance of a rule
violation in a single file and will typically be raised in response to circumstances which arise
during the development process.
Project Deviations should be reviewed regularly and this review should be a part of the formal deviation
process.
Many, if not most, of the circumstances where rules need to be broken are concerned with input/output
operations. It is recommended that the software be designed such that input/output concerns are
separated from the other parts of the software. As far as possible Project Deviations should then be
restricted to this input/output section of the code. Code subject to Project Deviations should be clearly
marked as such.
The purpose of this document is to avoid problems by thinking carefully about the issues and taking all
responsible measures to avoid the problems. The deviation procedure should not be used to undermine
this intention. In following the rules in this document the developer is taking advantage of the effort
expended by MISRA in understanding these issues. If the rules are to be deviated from, then the
developer is obliged to understand the issues for themselves. All deviations, standing and specific,
should be documented.
For example, if it is known beforehand that it will be difficult to adhere to a rule, the software
developer should submit a written Project Deviation Request and agreement with the customer should
be obtained prior to programming.
A Project Deviation Request should include the following:
13
A compliance matrix has been completed which shows how compliance has been enforced
All of the C code in the product is compliant with the rules of this document or subject to
documented deviations
A list of all instances of rules not being followed is being maintained, and for each instance
there is an appropriately signed-off deviation
14
15
16
<number> Every rule has a unique number. This number consists of a rule group prefix and a
group member suffix.
<source ref> This indicates the primary source(s) which led to this item or group of items,
where applicable. See section 5.5 for an explanation of the significance of these references, and
a key to the source materials.
In addition, supporting text is provided for each item or group of related items. The text gives, where
appropriate, some explanation of the underlying issues being addressed by the rule(s), and examples of
how to apply the rule(s). If there is no explanatory text immediately following a rule then the relevant
text will be found following the group of rules, and applies to all the rules which precede it. Similarly a
source reference following a group of rules applies to the whole group.
The supporting text is not intended as a tutorial in the relevant language feature, as the reader is assumed
to have a working knowledge of the language. Further information on the language features can be
obtained by consulting the relevant section of the language standard or other C language reference
books. Where a source reference is given for one or more of the Annex G items in the ISO standard,
then the original issue raised in the ISO standard may provide additional help in understanding the rule.
Within the rules and their supporting text the following font styles are used to represent C keywords and
C code:
C keywords appear in italic text
C code appears in a monospaced font, either within other text or as
separate code fragments;
Note that where code is quoted the fragments may be incomplete (for example an if statement without
its body). This is for the sake of brevity.
17
Non-specific variable names are constructed to give an indication of the type. For example:
uint8_t
sint32_t
u8a;
s32a;
Source
Annex G of ISO 9899 [2]
Unspecified
Undefined
Implementation
Locale
MISRA Guidelines
K&R
Koenig
IEC 61508
18
Annex G of ISO 9899 references: The number of the item in the relevant section of the Annex,
numbered from the beginning of that section. So for example [Locale 2] is the second item in
section G.4 of the standard.
In other references the relevant page number is given (unless stated otherwise).
Where a rule is based on issues from Annex G of the ISO C standard, it is helpful for the reader to
understand the distinction between unspecified, undefined, implementation-defined and
locale-specific issues. These are explained briefly here, and further information can be found in
Hatton [3].
5.5.2.1 Unspecified
These are language constructs that must compile successfully, but in which the compiler writer has some
freedom as to what the construct does. An example of this is the order of evaluation described in
Rule 12.2. There are 22 such issues.
It is unwise to place any reliance on the compiler behaving in a particular way. The compiler need not
even behave consistently across all possible constructs.
5.5.2.2 Undefined
These are essentially programming errors, but for which the compiler writer is not obliged to provide
error messages. Examples are invalid parameters to functions, or functions whose arguments do not
match the defined parameters.
These are particularly important from a safety point of view, as they represent programming errors
which may not necessarily by trapped by the compiler.
5.5.2.3 Implementation-defined
These are a bit like the unspecified issues, the main difference being that the compiler writer must take
a consistent approach and document it. In other words the functionality can vary from one compiler to
another, making code non-portable, but on any one compiler the behaviour should be well defined. An
example of this is the behaviour of the integer division and remainder operators / and % when
applied to one positive and one negative integer. There are 76 such issues.
These tend to be less critical from a safety point of view, provided the compiler writer has fully
documented their approach and then stuck to what they have implemented. It is advisable to avoid these
issues where possible.
19
20
6. Rules
6. Rules
6.1 Environment
Rule 1.1 (required):
These guidelines are based on ISO 9899:1990 [2] amended and corrected by ISO/IEC 9899/COR1:1995
[4], ISO/IEC 9899/AMD1:1995 [5], and ISO/IEC 9899/COR2:1996 [6]. No claim is made as to their
suitability with respect to the ISO 9899:1999 [8] version of the standard. Any reference in this document
to Standard C refers to the older ISO 9899:1990 [2] standard.
It is recognised that it will be necessary to raise deviations (as described in section 4.3.2) to permit
certain language extensions, for example to support hardware specific features.
Deviations are required if the environmental limits as specified in ISO 9899:1990 5.2.4 [2] are
exceeded, other than as allowed by Rule 5.1.
Rule 1.2 (required):
This rule requires that any reliance on undefined and unspecified behaviour, which is not specifically
addressed by other rules, shall be avoided. Where a specific behaviour is explicitly covered in another
rule, only that specific rule needs to be deviated if required. See ISO 9899:1990 Appendix G [2] for a
complete list of these issues.
Rule 1.3 (required):
21
6. Rules (continued)
Rule 1.4 (required):
The ISO standard requires external identifiers to be distinct in the first 6 characters. However
compliance with this severe and unhelpful restriction is considered an unnecessary limitation since most
compilers/linkers allow at least 31 character significance (as for internal identifiers).
The compiler/linker must be checked to establish this behaviour. If the compiler/linker is not capable of
meeting this limit, then use the limit of the compiler.
Rule 1.5 (advisory):
Floating-point arithmetic has a range of problems associated with it. Some (but not all) of the problems
can be overcome by using an implementation that conforms to a recognised standard. An example of an
appropriate standard is ANSI/IEEE Std 754 [21].
The definition of the floating-point types, in accordance with Rule 6.3, provides an opportunity for
noting the floating-point standard in use, for example:
/* IEEE 754 single-precision floating-point */
typedef float float32_t;
NOP")
This excludes the use of // C99 style comments and C++ style comments, since these are not permitted
in C90. Many compilers support the // style of comments as an extension to C90. The use of // in
preprocessor directives (e.g. #define) can vary. Also the mixing of /* ... */ and // is not consistent. This
is more than a style issue, since different (pre C99) compilers may behave differently.
22
6. Rules (continued)
Rule 2.3 (required):
C does not support the nesting of comments even though some compilers support this as a language
extension. A comment begins with /* and continues until the first */ is encountered. Any /* occurring
inside a comment is a violation of this rule. Consider the following code fragment:
/* some comment, end comment marker accidentally omitted
<<New Page>>
Perform_Critical_Safety_Function(X);
/* this comment is not compliant */
In reviewing the page containing the call to the function, the assumption is that it is executed code.
Because of the accidental omission of the end comment marker, the call to the safety critical function
will not be executed.
Rule 2.4 (advisory):
Where it is required for sections of source code not to be compiled then this should be achieved by use
of conditional compilation (e.g. #if or #ifdef constructs with a comment). Using start and end comment
markers for this purpose is dangerous because C does not support nested comments, and any comments
already existing in the section of code would change the effect.
6.3 Documentation
Rule 3.1 (required):
This rule requires that any reliance on implementation-defined behaviour, which is not specifically
addressed by other rules, shall be documented, for example by reference to compiler documentation.
Where a specific behaviour is explicitly covered in another rule, only that specific rule needs to be
deviated if required. See ISO 9899:1990 Appendix G [2] for a complete list of these issues.
Rule 3.2 (required):
For example, ISO 10646 [22] defines an international standard for mapping character sets to numeric
values. For portability, character-constants and string-literals should only contain characters that map to
a documented subset.
23
6. Rules (continued)
Rule 3.3 (advisory):
Potentially an ISO compliant compiler can do one of two things when dividing two signed integers, one
of which is positive and one negative. Firstly it may round up, with a negative remainder (e.g. -5/3 = -1
remainder -2), or secondly it may round down with a positive remainder (e.g. -5/3 = -2 remainder +1).
It is important to determine which of these is implemented by the compiler and to document it for
programmers, especially if it is the second (perhaps less intuitive) implementation.
Rule 3.4 (required):
This rule places a requirement on the user of this document to produce a list of any pragmas they choose
to use in an application. The meaning of each pragma shall be documented. There shall be sufficient
supporting description to demonstrate that the behaviour of the pragma, and its implications for the
application, have been fully understood.
Any use of pragmas should be minimised, localised and encapsulated within dedicated functions
wherever possible.
Rule 3.5 (required):
This is a particular problem where bit fields are used because of the poorly defined aspects of bit fields
described under Rules 6.4 and 6.5. The bit field facility in C is one of the most poorly defined parts of
the language. There are two main uses to which bit fields could be put:
To access the individual bits, or groups of bits, in larger data types (in conjunction with unions).
This use is not permitted (see Rule 18.4)
The packing together of short-length data to economise on storage is the only acceptable use of bit fields
envisaged in this document. Provided the elements of the structure are only ever accessed by their name,
the programmer needs to make no assumptions about the way that the bit fields are stored within the
structure.
It is recommended that structures be declared specifically to hold the sets of bit fields, and do not include
any other data within the same structure. Note that Rule 6.3 need not be followed in defining bit-fields,
since their lengths are specified in the structure.
If the compiler has a switch to force bit fields to follow a particular layout then this could assist in such
a justification.
24
6. Rules (continued)
For example the following is acceptable:
struct message
{
signed
int
unsigned int
unsigned int
} message_chunk;
If using bit fields, be aware of the potential pitfalls and areas of implementation-defined (i.e.
non-portable) behaviour. In particular the programmer should be aware of the following:
The alignment of the bit fields in the storage unit is implementation-defined, that is whether
they are allocated from the high end or low end of the storage unit (usually a byte).
Whether or not a bit field can overlap a storage unit boundary is also implementation-defined
(e.g. if a 6-bit field and a 4-bit field are declared in that order, whether the 4-bit field will start
a new byte or whether it will be 2 bits in one byte and 2 bits in the next).
This rule refers to any libraries used in the production code, which therefore may include standard
libraries supplied with the compiler, other third-party libraries, or libraries designed in-house. This is
recommended by IEC 61508 Part 3.
Only those escape sequences that are defined in the ISO C standard
shall be used.
[Undefined 11; Implementation 11]
See section 5.2.2 of the ISO standard for valid escape sequences.
Rule 4.2 (required):
Trigraphs are denoted by a sequence of 2 question marks followed by a specified third character (e.g.
??- represents a ~ (tilde) character and ??) represents a ]). They can cause accidental confusion
with other uses of two question marks. For example the string
"(Date should be in the form ??-??-??)"
25
6. Rules (continued)
6.5 Identifiers
Rule 5.1 (required):
The ISO standard requires internal identifiers to be distinct in the first 31 characters to guarantee code
portability. This limitation shall not be exceeded, even if the compiler supports it.
The ISO standard requires external identifiers to be distinct in the first 6 characters, regardless of case,
to guarantee optimal portability. However this limitation is particularly severe and is considered
unnecessary. The intent of this rule is to sanction a relaxation of the ISO requirement to a degree
commensurate with modern environments and it shall be confirmed that 31 character/case significance
is supported by the implementation.
Note that there is a related issue with using identifier names that differ by only one or a few characters,
especially if the identifier names are long. The problem is heightened if the differences are in easily
mis-read characters like 1 (one) and l (lower case L), 0 and O, 2 and Z, 5 and S, or n and h. It is
recommended to ensure that identifier names are always easily visually distinguishable. Specific
guidelines on this issue could be placed in the style guidelines (see section 4.2.2).
Rule 5.2 (required):
The terms outer and inner scope are defined as follows. Identifiers that have file scope can be considered as having the outermost scope. Identifiers that have block scope have a more inner scope.
Successive, nested blocks, introduce more inner scopes. The rule is only to disallow the case where a
second inner definition hides an outer definition. If the second definition does not hide the first definition, then this rule is not violated.
Hiding identifiers with an identifier of the same name in a nested scope leads to code that is very
confusing. For example:
int16_t i;
{
int16_t i;
i = 3;
No typedef name shall be reused either as a typedef name or for any other purpose.
26
6. Rules (continued)
For example:
{
typedef unsigned char uint8_t;
}
{
typedef unsigned char uint8_t;
}
{
unsigned char uint8_t;
typedef names shall not be reused anywhere within a program. Where the type definition is made in a
header file, and that header file is included in multiple source files, this rule is not a violated.
Rule 5.4 (required):
No tag name shall be reused either to define a different tag or for any other purpose within the program.
ISO 9899:1990 [2] does not define the behaviour when an aggregate declaration uses a tag in different
forms of type specifier (struct or union). Either all uses of the tag should be in structure type specifiers,
or all uses should be in union type specifiers, For example:
struct stag { uint16_t a; uint16_t b; };
struct stag a1 = { 0, 0 };
union stag a2 = { 0, 0 };
void foo(void)
{
struct stag { uint16_t a; }; /* Not compliant - tag stag redefined
}
*/
Where the type definition is made in a header file, and that header file is included in multiple source files,
this rule is not violated.
Rule 5.5 (advisory):
Regardless of scope, no identifier with static storage duration should be re-used across any source files
in the system. This includes objects or functions with external linkage and any objects or functions with
the static storage class specifier.
While the compiler can understand this and is in no way confused, the possibility exists for the user to
incorrectly associate unrelated variables with the same name.
One example of this confusion is having an identifier name with internal linkage in one file and the same
identifier name with external linkage in another file.
27
6. Rules (continued)
Rule 5.6 (advisory):
Name space and scope are different. This rule is not concerned with scope. For example, ISO C allows
the same identifier (vector) for both a tag and a typedef at the same scope.
typedef struct vector { uint16_t x ; uint16_t y; uint16_t z; } vector;
/* Rule violation ^^
^^ */
ISO C defines a number of different name spaces (see ISO 9899:1990 6.1.2.3 [2]). It is technically
possible to use the same name in separate name spaces to represent completely different items. However
this practice is deprecated because of the confusion it can cause, and so names should not be reused, even
in separate name spaces.
The example below illustrates a violation of this rule in which value is inadvertently used instead of
record.value:
struct { int16_t key; int16_t value; } record;
int16_t value; /* Rule violation - 2nd use of value */
record.key = 1;
value = 0;
/*
By contrast, the example below does not violate the rule because two member names are less likely to
be confused:
struct device_q { struct device_q *next; /* ... */ }
devices[N_DEVICES];
struct task_q { struct task_q *next; /* ... */ }
tasks[N_TASKS];
devices[0].next = &devices[1];
tasks[0].next
= &tasks[1];
Regardless of scope, no identifier should be re-used across any files in the system. This rule incorporates
the provisions of Rules 5.2, 5.3, 5.4, 5.5 and 5.6.
struct air_speed
{
uint16_t speed; /* knots */
} * x;
struct gnd_speed
{
uint16_t speed; /* mph
*/
/* Not Compliant - speed is in different units */
} * y;
x->speed = y->speed;
28
6. Rules (continued)
Where an identifier name is used in a header file, and that header file is included in multiple source files,
this rule is not violated. The use of a rigorous naming convention can support the implementation of this
rule.
6.6 Types
Rule 6.1 (required):
The plain char type shall be used only for the storage and use of
character values.
[Implementation 14]
signed and unsigned char type shall be used only for the storage and
use of numeric values.
There are three distinct char types, (plain) char, signed char and unsigned char. signed char and
unsigned char shall be used for numeric data and plain char shall be used for character data. The
signedness of the plain char type is implementation-defined and should not be relied upon.
The only permissible operators on plain char types are assignment and equality operators (=, ==, != ).
Rule 6.3 (advisory):
The basic numerical types of char, int, short, long, float and double should not be used, but
specific-length typedefs should be used. Rule 6.3 helps to clarify the size of the storage, but does not
guarantee portability because of the asymmetric behaviour of integral promotion. See discussion of
integral promotion section 6.10. It is still important to understand the integer size of the
implementation.
Programmers should be aware of the actual implementation of the typedefs under these definitions.
For example, the ISO (POSIX) typedefs as shown below are recommended and are used for all basic
numerical and character types in this document. For a 32-bit integer machine, these are as follows.
typedef
typedef
typedef
typedef
typedef
typedef
typedef
typedef
typedef
typedef
typedef
typedef
signed
signed
signed
signed
unsigned
unsigned
unsigned
unsigned
long
char
char
short
int
long
char
short
int
long
float
double
double
char_t;
int8_t;
int16_t;
int32_t;
int64_t;
uint8_t;
uint16_t;
uint32_t;
uint64_t;
float32_t;
float64_t;
float128_t;
29
6. Rules (continued)
Rule 6.4 (required):
Using int is implementation-defined because bit fields of type int can be either signed or unsigned. The
use of enum, short or char types for bit fields is not allowed because the behaviour is undefined.
Rule 6.5 (required):
6.7 Constants
Rule 7.1 (required):
Octal constants (other than zero) and octal escape sequences shall
not be used.
[Koenig 9]
Any integer constant beginning with a 0 (zero) is treated as octal. So there is a danger, for example,
with writing fixed length constants. For example, the following array initialisation for 3-digit bus
messages would not do as expected (052 is octal, i.e. 42 decimal):
code[1]
code[2]
code[3]
code[4]
=
=
=
=
109;
100;
052;
071;
/*
/*
/*
/*
equivalent
equivalent
equivalent
equivalent
to
to
to
to
decimal
decimal
decimal
decimal
109 */
100 */
42 */
57 */
Octal escape sequences can be problematic because the inadvertent introduction of a decimal digit ends
the octal escape and introduces another character. The value of the first expression in the following
example is implementation-defined because the character constant consists of two characters, \10 and
9. The second character constant expression below contains the single character \100. Its value will
be implementation-defined if character 64 is not represented in the basic execution character set.
code[5] = '\109'; /* implementation-defined, two character constant */
code[6] = '\100'; /* set to 64, or implementation-defined
*/
It is better not to use octal constants or escape sequences at all, and to statically check for any
occurrences. The integer constant zero (written as a single numeric digit), is strictly speaking an octal
constant, but is a permitted exception to this rule.
30
6. Rules (continued)
6.8 Declarations and definitions
Rule 8.1 (required):
The use of prototypes enables the compiler to check the integrity of function definitions and calls.
Without prototypes the compiler is not obliged to pick up certain errors in function calls (e.g. different
number of arguments from the function body, mismatch in types of arguments between call and
definition). Function interfaces have been shown to be a cause of considerable problems, and therefore
this rule is considered very important.
The recommended method of implementing function prototypes for external functions is to declare the
function (i.e. give the function prototype) in a header file, and then include the header file in all those
code files that need the prototype (see Rule 8.8).
The provision of a prototype for a function with internal linkage is a good programming practice.
Rule 8.2 (required):
extern
x;
extern int16_t x;
const
y;
const int16_t y;
static
foo(void);
static int16_t foo(void);
/*
/*
/*
/*
/*
/*
*/
*/
*/
*/
*/
*/
For each function parameter the type given in the declaration and
definition shall be identical, and the return types shall also be
identical.
[Undefined 24; Koenig 5962]
The types of the parameters and return values in the prototype and the definition must match. This
requires identical types including typedef names and qualifiers, and not just identical base types.
Rule 8.4 (required):
If objects or functions are declared more than once their types shall
be compatible.
[Undefined 10]
The definition of compatible types is lengthy and complex (ISO 9899:1990 [2], sections 6.1.2.6, 6.5.2,
6.5.3 and 6.5.4 give full details). Two identical types are compatible but two compatible types need not
be identical. For example, the following pairs of types are compatible:
signed int
char [5]
unsigned short int
int
char []
unsigned short
31
6. Rules (continued)
Rule 8.5 (required):
Header files should be used to declare objects, functions, typedefs, and macros. Header files shall not
contain or produce definitions of objects or functions (or fragment of functions or objects) that occupy
storage. This makes it clear that only C files contain executable source code and that header files only
contain declarations.
Rule 8.6 (required):
Declaring functions at block scope may be confusing, and can lead to undefined behaviour.
Rule 8.7 (required):
Objects shall be defined at block scope if they are only accessed from
within a single function.
The scope of objects shall be restricted to functions where possible. File scope shall only be used where
objects need to have either internal or external linkage. Where objects are declared at file scope Rule
8.10 applies. It is considered good practice to avoid making identifiers global except where necessary.
Whether objects are declared at the outermost or innermost block is largely a matter of style.
Rule 8.8 (required):
Normally this will mean declaring an external identifier in a header file, that will be included in any file
where the identifier is defined or used. For example:
extern int16_t a;
There may be one or there may be many header files in a project, but each external object or function
shall only be declared in one header file.
Rule 8.9 (required):
Behaviour is undefined if an identifier is used for which multiple definitions exist (in different files) or
no definition exists at all. Multiple definitions in different files are not permitted even if the definitions
are the same, and it is obviously serious if they are different, or initialise the identifier to different
values.
32
6. Rules (continued)
Rule 8.10 (required):
If a variable is only to be used by functions within the same file then use static. Similarly if a function
is only called from elsewhere within the same file, use static. Use of the static storage-class specifier will
ensure that the identifier is only visible in the file in which it is declared and avoids any possibility of
confusion with an identical identifier in another file or a library.
Rule 8.11 (required):
The static and extern storage class specifiers can be a source of confusion. It is good practice to apply
the static keyword consistently to all declarations of objects and functions with internal linkage.
Rule 8.12 (required):
int array1[ 10 ];
extern int array2[ ];
int array2[ ] = { 0, 10, 15 };
/* Compliant
*/
/* Not compliant */
/* Compliant
*/
Although it is possible to declare an array of incomplete type and access its elements, it is safer to do so
when the size of the array may be explicitly determined.
6.9 Initialisation
Rule 9.1 (required):
The intent of this rule is that all variables shall have been written to before they are read. This does not
necessarily require initialisation at declaration.
Note that according to the ISO C standard, variables with static storage duration are automatically
initialised to zero by default, unless explicitly initialised. In practice, many embedded environments do
not implement this behaviour. Static storage duration is a property of all variables declared with the
static storage class specifier, or with external linkage. Variables with automatic storage duration are not
usually automatically initialised.
33
6. Rules (continued)
Rule 9.2 (required):
ISO C requires initialiser lists for arrays, structures and union types to be enclosed in a single pair of
braces (though the behaviour if this is not done is undefined). The rule given here goes further in
requiring the use of additional braces to indicate nested structures. This forces the programmer to
explicitly consider and demonstrate the order in which elements of complex data types are initialised
(e.g. multi-dimensional arrays).
For example, below are two valid (in ISO C) ways of initialising the elements of a two dimensional
array, but the first does not adhere to the rule:
int16_t y[3][2] = { 1, 2, 3, 4, 5, 6 };
int16_t y[3][2] = { { 1, 2 }, { 3, 4 }, { 5, 6 } };
/* not compliant */
/* compliant
*/
A similar principle applies to structures, and nested combinations of structures, arrays and other types.
Note also that all the elements of arrays or structures can be initialised (to zero or NULL) by giving an
explicit initialiser for the first element only. If this method of initialisation is chosen then the first
element should be initialised to zero (or NULL), and nested braces need not be used.
The ISO standard [2] contains extensive examples of initialisation.
Rule 9.3 (required):
If an enumerator list is given with no explicit initialisation of members, then C allocates a sequence of
integers starting at 0 for the first element and increasing by 1 for each subsequent element.
An explicit initialisation of the first element, as permitted by the above rule, forces the allocation of
integers to start at the given value. When adopting this approach it is essential to ensure that the
initialisation value used is small enough that no subsequent value in the list will exceed the int storage
used by enumeration constants.
Explicit initialisation of all items in the list, which is also permissible, prevents the mixing of automatic
and manual allocation, which is error prone. However it is then the responsibility of the programmer to
ensure that all values are in the required range, and that values are not unintentionally duplicated.
enum colour { red=3, blue, green, yellow=5 };
/* non compliant */
/* green and yellow represent the same value - this is duplication */
enum colour { red=3, blue=4, green=5, yellow=5 };
/* compliant */
/* green and yellow represent the same value - this is duplication */
34
6. Rules (continued)
6.10 Arithmetic type conversions
6.10.1 Implicit and explicit type conversions
The C language allows the programmer considerable freedom and will allow conversions between
different arithmetic types to be performed automatically. An explicit cast may be introduced for
functional reasons, for example:
The insertion of a cast for purposes of clarification is often helpful, but when taken to excess, the
practice can lead to unreadable code. As demonstrated below, there are some implicit conversions that
can safely be ignored and others that cannot.
6.10.2 Types of implicit conversion
There are three particular categories of implicit type conversion that need to be distinguished.
Integral promotion is frequently confused with balancing of operands (described below). In fact,
integral promotion takes place in unary operations and it takes place in binary operations where both
operands are of the same type.
35
6. Rules (continued)
Because of integral promotion, the result of adding two objects of type unsigned short is always a value
of type signed int or unsigned int; in fact, the addition is performed in that type. It is therefore possible
for such an operation to derive a result whose value exceeds the size that could be accommodated in the
original type of the operands. For example, if the size of an int is 32 bits, it is possible to multiply two
objects of type short (16 bits) and derive a 32-bit result with no danger of overflow. On the other hand
if the size of an int is only 16 bits, the product of two 16-bit objects will only yield a 16-bit result and
appropriate restrictions must be placed on the size of the operands.
Integral promotion also applies to unary operators. For example, the result of applying a bitwise
negation operator (~) to an unsigned char operand is typically a negative value of type signed int.
Integral promotion is a fundamental inconsistency in the C language whereby the small integer types
behave differently from long and int types. The use of typedefs is a practice that is encouraged in
MISRA-C. However, because the behaviour of the various integer types is not consistent, it can be
unsafe to ignore the underlying base types (see description on following pages) unless some restrictions
are placed on the way in which expressions are constructed. It is the intention of the following rules that
the effects of integral promotion should be neutralised in order to avoid these anomalies.
Assigning conversions
Assigning conversions occur when:
The type of an assignment expression is converted to the type of the assignment object
The type of an initialiser expression is converted to the type of the initialised object
The type of a function call argument is converted to the type of the formal parameter as
declared in the function prototype
The type of the expression used in a return statement is converted to the type of the function as
declared in the function prototype
The type of the constant expression in a switch case label is converted to the promoted type of
the controlling expression. This conversion is performed only for the purposes of comparison
In each case, the value of an arithmetic expression is unconditionally converted, where necessary, to
another type.
Balancing conversions
Balancing conversions are described in the ISO C standard under the term Usual Arithmetic
Conversions. This is a set of rules which provides a mechanism to yield a common type when two
operands of a binary operator are balanced to a common type or the second and third arguments of the
conditional operator ( ? : ) are balanced to a common type. Balancing conversions always involve two
operands of different type; one and sometimes both operands will be subject to an implicit conversion.
36
6. Rules (continued)
The balancing rules are complicated by the process of integral promotion (described above) under which
any operand of a small integer type is first promoted to type int or unsigned int. Integral promotion
happens as part of the usual arithmetic conversions even when two operands are of identical type.
The operators explicitly associated with balancing conversions are:
Multiplicative *, /, %
Additive +, -
Bitwise &, ^, |
Most of these operators yield a result that is the type resulting from the balancing process. Relational and
equality operators are the exception in that they yield a Boolean value result of type int.
Notice that the operands of the bitwise shift operators (<< and >>) are not balanced. The type of the result
is the promoted type of the first operand; the second operand may be of any signed or unsigned integer
type.
6.10.3 Dangerous type conversions
There are a number of potential dangers associated with type conversions that it is necessary to avoid:
Loss of value: Conversion to a type where the magnitude of the value cannot be
represented
Loss of sign: Conversion from a signed type to an unsigned type resulting in loss of sign
Loss of precision: Conversion from a floating type to an integer type with consequent loss
of precision
The only type conversions that can be guaranteed safe for all data values and all possible conforming
implementations are:
Of course, in practice, if assumptions are about typical type sizes, it is possible to classify other type
conversions as safe. In general, MISRA-C:2004 adopts the principle that it is wise to identify
potentially dangerous type conversions by making the conversion explicit.
37
6. Rules (continued)
There are some other dangers in the area of type conversion that also need to be recognised. These are
issues that arise from areas of misunderstanding and difficulty in the C language rather than because data
values are not preserved.
Type widening in integral promotion: The type in which integral expressions are evaluated
depends on the type of the operands after any integral promotion. It is always possible to
multiply two 8-bit values and access a 16-bit result if the magnitude requires it. It is sometimes,
but not always, possible to multiply two 16-bit values and retrieve a 32-bit result. This is a
dangerous inconsistency in the C language and in order to avoid confusion it is safer never to
rely on the widening type afforded by integral promotion. Consider the following example:
uint16_t u16a = 40000;
uint16_t u16b = 30000;
uint32_t u32x;
*/
The expected result is presumably 70000, but the value assigned to u will in practice
depend on the implemented size of an int. If the implemented size of an int is 32 bits, the
addition will occur in 32-bit signed arithmetic and the correct value will be stored. If the
implemented size of an int is only 16 bits, the addition will take place in 16-bit unsigned
arithmetic, wraparound will occur and will yield the value 4464 (70000 % 65536). Wraparound
in unsigned arithmetic is well defined and may even be intended; but there is potential for
confusion.
Evaluation type confusion: A similar problem arises from a common misconception among
programmers that the type in which a calculation is conducted is influenced in some way by
the type to which the result is assigned or converted. For example, in the following code the
two 16-bit objects are added together in 16-bit arithmetic (unless promoted to 32-bit int by
integral promotion), and the result is converted to type uint32_t on assignment.
u32x = u16a + u16b;
It is not unusual for programmers to be deceived into thinking that the addition is performed
in 32-bit arithmetic because of the type of u32x.
Confusion of this nature is not confined to integer arithmetic or to implicit conversions. The
following examples demonstrate some statements in which the result is well defined but the
calculation may not be performed in the type that the programmer assumes.
u32a
f64a
f32a
f64a
f64a
=
=
=
=
=
(uint32_t)(u16a * u16b);
u16a / u16b;
(float32_t)(u16a / u16b);
f32a + f32b;
(float64_t)(f32a + f32b);
38
6. Rules (continued)
Change of signedness in arithmetic operations: Integral promotion will often result in two
unsigned operands yielding a result of type (signed) int. For example, the addition of two
16-bit unsigned operands will yield a signed 32-bit result if int is 32 bits but an unsigned
16-bit result if int is 16 bits.
Change of signedness in bitwise operations: Integral promotion can have some particularly
unfortunate repercussions when bitwise operators are applied to small unsigned types. For
example a bitwise complement operation on an operand of type unsigned char will generally
yield a result of type (signed) int with a negative value. The operand is promoted to type int
before the operation and the extra high order bits are set by the complement process. The
number of extra bits, if any, is dependent on the size of an int and it is hazardous if the
complement operation is followed by a right shift.
In order to avoid the perils associated with the issues described above, it is important to establish some
principles to constrain the way in which expressions are constructed. Firstly, definitions of some
concepts are given.
6.10.4 Underlying type
The type of an expression refers to the type of the value obtained when the expression is evaluated. When
two items of type long are added, the expression has type long. Most arithmetic operators derive a result
whose type is dependent on the type of the operands. On the other hand, there are some operators that
yield a Boolean result of type int regardless of the type of the operands. So, for example, when two items
of type long are compared with a relational operator the expression has type int.
The term underlying type is defined as describing the type that would be obtained from evaluating an
expression if it were not for the effects of integral promotion.
When two operands of type int are added the result is of type int and the expression may be said to have
type int.
When two operands of type unsigned char are added the result is also (usually) of type int (because of
integral promotion), but the underlying type of the expression is defined to be unsigned char.
The term underlying type is not known in the C standard or in other texts on the C language but is
useful in describing some of the following rules. It describes a hypothetical departure from the C
language in which integral promotion does not exist and the usual arithmetic conversions are applied
consistently to all integer types. The concept is introduced because the effects of integral promotion are
subtle and sometimes dangerous. Integral promotion is an unavoidable feature of the C language, but the
intention of these rules is that the effect of integral promotion should be neutralised by taking no
advantage of the widening that occurs with small integer operands.
Of course, the C standard does not explicitly define how small integer types would be balanced to a
common type in the absence of integral promotion although it does establish the value-preserving
principles.
39
6. Rules (continued)
When adding operands of type int, the programmer is obliged to ensure that the result of the operation
will not exceed a value that can be represented in type int. If he fails to do so, overflow will occur and
the results are undefined. It is the intention of the approach described here that the same principle should
apply when small integer operands are added; the programmer should ensure that the result of adding
two unsigned chars is representable in an unsigned char, even though integral promotion could give rise
to evaluation in a larger type. In other words the limitations of the underlying type of an expression
should be observed rather than the actual type.
40
6. Rules (continued)
In a conventional architecture, the underlying type of an integer constant expression will be determined
according to its magnitude and signedness as follows:
Unsigned values
0U
to
255U
8 bit unsigned
256U
to
65535U
16 bit unsigned
65536U
to
4294967295U
32 bit unsigned
-2147483648
to
-32769
32 bit signed
-32768
to
-129
16 bit signed
-128
to
127
8 bit signed
128
to
32767
16 bit signed
32768
to
2147483647
32 bit signed
Signed values
Notice that underlying type is an artificial concept. It does not in any way influence the type of
evaluation that is actually performed. The concept has been developed simply as a way of defining a safe
framework in which to construct arithmetic expressions.
6.10.5 Complex expressions
The type conversion rules described in the following paragraphs refer in some places to the notion of a
complex expression. The term complex expression is defined to mean any expression that is not:
a constant expression
The conversions that may be applied to complex expressions are restricted in order to avoid some of the
dangers outlined above. Specifically it is required that a sequence of arithmetic operations in an
expression should be conducted in the same type.
41
6. Rules (continued)
The following expressions are complex:
s8a + s8b
~u16a
u16a >> 2
foo(2) + u8a
*ppc + 1
++u8a
The following expressions are not complex, even though some contain complex sub-expressions:
pc[u8a]
foo(u8a + u8b)
**ppuc
*(ppc + 1)
pcbuf[s16a * 2]
Notice also that in describing integer conversions, the concern is always with underlying type rather than
actual type.
These two rules broadly encapsulate the following principles:
42
6. Rules (continued)
The intention when restricting implicit conversion of complex expressions is to require that in a sequence
of arithmetic operations within an expression, all operations should be conducted in exactly the same
arithmetic type. Notice that this does not imply that all operands in an expression are of the same type.
The expression u32a + u16b + u16c is compliant both additions will notionally be performed in
type U32.
The expression u16a + u16b + u32c is not compliant the first addition is notionally performed in
type U16 and the second in type U32.
The word notionally is used because, in practice, the type in which arithmetic will be conducted will
depend on the implemented size of an int. By observing the principle whereby all operations are
performed in a consistent (underlying) type, it is possible to avoid programmer confusion and some of
the dangers associated with integral promotion.
extern void foo1(uint8_t x);
int16_t t1(void)
{
...
foo1(u8a);
foo1(u8a + u8b);
foo1(s8a);
foo1(u16a);
foo1(2);
foo1(2U);
foo1((uint8_t)2);
... s8a + u8a
... s8a + (int8_t)u8a
s8b = u8a;
... u8a + 5
... u8a + 5U
... u8a + (uint8_t)5
u8a = u16a;
u8a = (uint8_t)u16a;
u8a = 5UL;
... u8a + 10UL
u8a = 5U;
... u8a + 3
... u8a >> 3
... u8a >> 3U
pca = "P";
... s32a + 80000
... s32a + 80000L
f32a = f64a;
f32a = 2.5;
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
compliant
*/
compliant
*/
not compliant */
not compliant */
not compliant */
compliant
*/
compliant
*/
not compliant */
compliant
*/
not compliant */
not compliant */
compliant
*/
compliant
*/
not compliant */
compliant
*/
not compliant */
compliant
*/
compliant
*/
not compliant */
compliant
*/
compliant
*/
compliant
*/
compliant
*/
compliant
*/
not compliant */
not compliant unsuffixed floating
constants are of type
double */
/* compliant
*/
/* not compliant */
43
6. Rules (continued)
s32a = u8b + u8c;
f32a = 2.5F;
u8a = f32a;
s32a = 1.0;
f32a = 1;
f32a = s16a;
... f32a + 1
... f64a * s32a
...
return (s32a);
...
return (s16a);
...
return (20000);
...
return (20000L);
...
return (s8a);
...
return (u16a);
/*
/*
/*
/*
/*
/*
/*
/*
not compliant
compliant
not compliant
not compliant
not compliant
not compliant
not compliant
not compliant
*/
*/
*/
*/
*/
*/
*/
*/
/* not compliant */
/* compliant
*/
/* compliant
*/
/* not compliant */
/* not compliant */
/* not compliant */
}
int16_t foo2(void)
{
...
... (u16a + u16b) + u32a
... s32a + s8a + s8b
... s8a + s8b + s32a
f64a = f32a + f32b;
f64a = f64b + f32a;
f64a = s32a / s32b;
u32a = u16a + u16a;
s16a = s8a;
s16a = s16b + 20000;
s32a = s16a + 20000;
s32a = s16a + (int32_t)20000;
u16a = u16b + u8a;
foo1(u16a);
foo1(u8a + u8b);
...
return s16a;
...
return s8a;
}
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
not compliant
compliant
not compliant
not compliant
compliant
not compliant
not compliant
compliant
compliant
not compliant
compliant
compliant
not compliant
compliant
/* compliant
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
/* not compliant */
44
6. Rules (continued)
6.10.7 Explicit conversions (casts)
Rule 10.3 (required):
If a cast is to be used on any complex expression, the type of cast that may be applied is severely
restricted. As explained in section 6.10, conversions on complex expressions are often a source of
confusion and it is therefore wise to be cautious. In order to comply with these rules, it may be
necessary to use a temporary variable and introduce an extra statement.
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
(float32_t)(f64a + f64b)
(float64_t)(f32a + f32b)
(float64_t)f32a
(float64_t)(s32a / s32b)
(float64_t)(s32a > s32b)
(float64_t)s32a / (float32_t)s32b
(uint32_t)(u16a + u16b)
(uint32_t)u16a + u16b
(uint32_t)u16a + (uint32_t)u16b
(int16_t)(s32a - 12345)
(uint8_t)(u16a * u16b)
(uint16_t)(u8a * u8b)
(int16_t)(s32a * s32b)
(int32_t)(s16a * s16b)
(uint16_t)(f64a + f64b)
(float32_t)(u16a + u16b)
(float64_t)foo1(u16a + u16b)
(int32_t)buf16a[u16a + u16b]
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
compliant
not compliant
compliant
not compliant
not compliant
compliant
not compliant
compliant
compliant
compliant
compliant
not compliant
compliant
not compliant
not compliant
not compliant
compliant
compliant
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
*/
When these operators (~ and <<) are applied to small integer types (unsigned char or unsigned short),
the operations are preceded by integral promotion, and the result may contain high order bits which have
not been anticipated. For example:
uint8_t port = 0x5aU;
uint8_t result_8;
uint16_t result_16;
uint16_t mode;
result_8 = (~port) >> 4;
/* not compliant */
45
6. Rules (continued)
~port is 0xffa5 on a 16-bit machine but 0xffffffa5 on a 32-bit machine. In either case the value of
result is 0xfa, but 0x0a may have been expected. This danger is avoided by inclusion of the cast as
shown below:
result_8 = ((uint8_t)(~port)) >> 4 ;
result_16 = ((uint16_t)(~(uint16_t)port)) >> 4 ;
/* compliant */
/* compliant */
A similar problem exists when the << operator is used on small integer types and high order bits are
retained. For example:
result_16 = ((port << 4) & mode) >> 6;
/* not compliant */
The value in result_16 will depend on the implemented size of an int. Addition of a cast avoids any
ambiguity.
result_16 = ((uint16_t)((uint16_t)port << 4) & mode) >> 6;
/* compliant */
The type of an integer constant is a potential source of confusion, because it is dependent on a complex
combination of factors including:
The number base in which the value is expressed (i.e. decimal, octal or hexadecimal)
For example, the integer constant 40000 is of type int in a 32-bit environment but of type long in a
16-bit environment. The value 0x8000 is of type unsigned int in a 16-bit environment, but of type
(signed) int in a 32-bit environment.
Note the following:
An unsuffixed hexadecimal value greater than or equal to 2 may be of signed or unsigned type
An unsuffixed decimal value greater than or equal to 2 may be of signed or unsigned type
31
But:
15
31
46
6. Rules (continued)
Signedness of constants should be explicit. Consistent signedness is an important principle in
constructing well formed expressions. If a constant is of an unsigned type, it is helpful to avoid
ambiguity by applying a U suffix. When applied to larger values, the suffix may be redundant (in the
sense that it does not influence the type of the constant); however its presence is a valuable contribution
towards clarity.
Pointer to object
Pointer to function
Pointer to void
The conversion is between a pointer to object and a pointer to void, and the destination type
carries all the type qualifiers of the source type
A null pointer constant (void *) is converted automatically to a particular pointer type when it
is assigned to or compared for equality with any type of pointer
Only certain types of pointer conversion are defined in C and the behaviour of some conversions is
implementation-defined.
Rule 11.1 (required):
Conversion of a function pointer to a different type of pointer results in undefined behaviour. This
means, for example, that a pointer to a function cannot be converted to a pointer to a different type of
function.
Rule 11.2 (required):
47
6. Rules (continued)
Rule 11.3 (advisory):
The size of integer that is required when a pointer is converted to an integer is implementation-defined.
Casting between a pointer and an integer type should be avoided where possible, but may be
unavoidable when addressing memory mapped registers or other hardware specific features.
Rule 11.4 (advisory):
Conversions of this type may be invalid if the new pointer type requires a stricter alignment.
uint8_t *
uint32_t *
p1;
p2;
p2 = (uint32_t *)p1;
/* Incompatible alignment ? */
Any attempt to remove the qualification associated with the addressed type by using casting is a
violation of the principle of type qualification. Notice that the qualification referred to here is not the
same as any qualification that may be applied to the pointer itself.
uint16_t
uint16_t * const
uint16_t * const
const uint16_t *
uint16_t *
const uint16_t
volatile uint16_t
uint16_t
...
pi = cpi;
pi
pi
ppi
ppi
=
=
=
=
(uint16_t
(uint16_t
(uint16_t
(uint16_t
*
*
*
*
*
*
x;
cpi = &x;
pcpi;
ppci;
ppi;
pci;
pvi;
pi;
*)pci;
*)pvi;
* *)pcpi;
* *)ppci;
/* const pointer
*/
/* pointer to const pointer
*/
/* pointer to pointer to const */
/* pointer to const
/* pointer to volatile
*/
*/
/* Compliant - no conversion
no cast required
/* Not compliant
/* Not compliant
/* Not compliant
/* Not compliant
*/
*/
*/
*/
*/
6.12 Expressions
Rule 12.1 (advisory):
48
6. Rules (continued)
In addition to the use of parentheses to override default operator precedence, parentheses should also be
used to emphasise it. It is easy to make a mistake with the rather complicated precedence rules of C, and
this approach helps to avoid such errors, and helps to make the code easier to read. However, do not add
too many parentheses so as to clutter the code and make it unreadable.
The following guidelines are suggested in deciding when parentheses are required:
no parentheses are required for the right-hand operand of an assignment operator unless the
right-hand side itself contains an assignment expression:
x = a + b;
x = (a + b);
/* acceptable
*/
/* () not required */
/* acceptable
*/
/* () not required */
otherwise, the operands of binary and ternary operators shall be cast-expressions (see section
6.3.4 of ISO 9899:1990 [2]) unless all the operators in the expression are the same.
x = a + b + c;
x = f (a + b, c);
x = (a == b) ? a : (a - b);
if (a && b && c)
x = (a + b) - (c + d);
x = (a * 3) + c + d;
x = (uint16_t) a + b;
*/
*/
even if all operators are the same, parentheses may be used to control the order of operation.
Some operators (e.g. addition and multiplication) that are associative in algebra are not
necessarily associative in C. Similarly, integer operations involving mixed types (prohibited by
several rules) may produce different results because of the integral promotions. The following
example written for a 16-bit implementation demonstrates that addition is not associative and
that it is important to be clear about the structure of an expression:
uint16_t
uint16_t
uint32_t
uint32_t
a = 10;
b = 65535;
c = 0;
d;
d = (a + b) + c;
/* d is 9; a + b wraps modulo 65536 */
d = a + (b + c);
/* d is 65545
*/
/* this example also deviates from several other rules */
Note that Rule 12.5 is a special case of this rule applicable solely to the logical operators, && and ||.
49
6. Rules (continued)
Rule 12.2 (required):
Apart from a few operators (notably the function call operator (), &&, ||, ?: and , (comma)) the order
in which sub-expressions are evaluated is unspecified and can vary. This means that no reliance can be
placed on the order of evaluation of sub-expressions, and in particular no reliance can be placed on the
order in which side effects occur. Those points in the evaluation of an expression at which all previous
side effects can be guaranteed to have taken place are called sequence points. Sequence points and side
effects are described in sections 5.1.2.3, 6.3 and 6.6 of ISO 9899:1990 [2].
Note that the order of evaluation problem is not solved by the use of parentheses, as this is not a
precedence issue.
The following notes give some guidance on how dependence on order of evaluation may occur, and
therefore may assist in adopting the rule.
This will give different results depending on whether b[i] is evaluated before i++ or vice
versa. The problem could be avoided by putting the increment operation in a separate statement.
The example would then become:
x = b[i] + i;
i++;
function arguments
The order of evaluation of function arguments is unspecified.
x = func( i++, i );
This will give different results depending on which of the functions two parameters is
evaluated first.
function pointers
If a function is called via a function pointer there shall be no dependence on the order in which
function designator and function arguments are evaluated.
p->task_start_fn(p++);
50
6. Rules (continued)
function calls
Functions may have additional effects when they are called (e.g. modifying some global data).
Dependence on order of evaluation could be avoided by invoking the function prior to the
expression that uses it, making use of a temporary variable for the value.
For example
x = f(a) + g(a);
could be written as
x = f(a);
x += g(a);
As an example of what can go wrong, consider an expression to get two values off a stack,
subtract the second from the first, and push the result back on the stack:
push( pop() - pop() );
This will give different results depending on which of the pop() function calls is evaluated first
(because pop() has side effects).
accessing a volatile
The volatile type qualifier is provided in C to denote objects whose value can change
independently of the execution of the program (for example an input register). If an object of
volatile qualified type is accessed this may change its value. C compilers will not optimise out
reads of a volatile. In addition, as far as a C program is concerned, a read of a volatile has a
side effect (changing the value of the volatile).
It will usually be necessary to access volatile data as part of an expression, which then means
there may be dependence on order of evaluation. Where possible though it is recommended that
volatiles only be accessed in simple assignment statements, such as the following:
volatile uint16_t v;
/* ... */
x = v;
51
6. Rules (continued)
The rule addresses the order of evaluation problem with side effects. Note that there may also be an issue
with the number of times a sub-expression is evaluated, which is not covered by this rule. This can be a
problem with function invocations where the function is implemented as a macro. For example,
consider the following function-like macro and its invocation:
#define MAX(a, b) ( ((a) > (b)) ? (a) : (b) )
/* ... */
z = MAX( i++, j );
The definition evaluates the first parameter twice if a > b but only once if a b. The macro invocation
may thus increment i either once or twice, depending on the values of i and j.
It should be noted that magnitude-dependent effects, such as those due to floating-point rounding, are
also not addressed by this rule. Although the order in which side-effects occur is undefined, the result of
an operation is otherwise well-defined and is controlled by the structure of the expression. In the
following example, f1 and f2 are floating-point variables; F3, F4 and F5 denote expressions with
floating-point types.
f1 = F3 + (F4 + F5);
f2 = (F3 + F4) + F5;
The addition operations are, or at least appear to be, performed in the order determined by the position
of the parentheses, i.e. first F4 is added to F5 then secondly F3 is added to give the value of f1. Provided
that F3, F4 and F5 contain no side-effects, their values are independent of the order in which they are
evaluated. However, the values assigned to f1 and f2 are not guaranteed to be the same because
floating-point rounding following the addition operations will depend on the values being added.
Rule 12.3 (required):
The sizeof operator shall not be used on expressions that contain side
effects.
A possible programming error in C is to apply the sizeof operator to an expression and expect the
expression to be evaluated. However the expression is not evaluated: sizeof only acts on the type of the
expression. To avoid this error, sizeof shall not be used on expressions that contain side effects, as the
side effects will not occur. For example:
int32_t i;
int32_t j;
j = sizeof(i = 1234);
/* j is set to the sizeof the type of i which is an int */
/* i is not set to 1234.
*/
52
6. Rules (continued)
There are some situations in C code where certain parts of expressions may not be evaluated. If these
sub-expressions contain side effects then those side effects may or may not occur, depending on the
values of other sub-expressions.
The operators which can lead to this problem are &&, || and ?:. In the case of the first two (logical
operators) the evaluation of the right-hand operand is conditional on the value of the left-hand operand.
In the case of the ?: operator, either the second or third operands are evaluated but not both. The
conditional evaluation of the right-hand operand of one of the logical operators can easily cause
problems if the programmer relies on a side effect occurring. The ?: operator is specifically provided to
choose between two sub-expressions, and is therefore less likely to lead to mistakes.
For example:
if ( ishigh && ( x == i++ ) )
if ( ishigh && ( x == f(x) ) )
/* Not compliant
*/
/* Only acceptable if f(x) is
known to have no side effects */
The operations that cause side effects are described in section 5.1.2.3 of ISO 9899:1990 [2] as accessing
a volatile object, modifying an object, modifying a file, or calling a function that does any of those
operations, which cause changes in the state of the execution environment of the calling function.
Rule 12.5 (required):
Primary expressions are defined in ISO 9899:1990 [2], section 6.3.1. Essentially they are either a
single identifier, or a constant, or a parenthesised expression. The effect of this rule is to require that if
an operand is other than a single identifier or constant then it must be parenthesised. Parentheses are
important in this situation both for readability of code and for ensuring that the behaviour is as the
programmer intended. Where an expression consists of either a sequence of only logical && or a sequence
of only logical ||, extra parentheses are not required.
For example write:
if ( ( x == 0 ) && ishigh ) /* make x == 0 primary
if ( x || y || z )
/* exception allowed, if x, y and z are
Boolean
if ( x || ( y && z ) )
/* make y && z primary
if ( x && ( !y ) )
/* make !y primary
if ( ( is_odd (y) ) && x ) /* make call primary
*/
*/
*/
*/
*/
Where an expression consists of either a sequence of only logical && or a sequence of only logical ||,
extra parentheses are not required.
if ( ( x > c1) && (y > c2) && (z > c3) )
/* Compliant
*/
if ( ( x > c1) && (y > c2) || (z > c3) )
/* not compliant
*/
if ( ( x > c1) && ((y > c2) || (z > c3)) ) /* Compliant extra () used */
53
6. Rules (continued)
Rule 12.6 (advisory):
The logical operators &&, || and ! can be easily confused with the bitwise operators &, | and ~.
See Boolean expressions in the glossary.
Rule 12.7 (required):
Bitwise operations (~, <<, >>, &, ^ and |) are not normally meaningful on signed integers. Problems can
arise if, for example, a right shift moves the sign bit into the number, or a left shift moves a numeric bit
into the sign bit.
See section 6.10 for a description of underlying type.
Rule 12.8 (required):
The right-hand operand of a shift operator shall lie between zero and
one less than the width in bits of the underlying type of the left-hand
operand.
[Undefined 32]
If, for example, the left-hand operand of a left-shift or right-shift is a 16-bit integer, then it is important
to ensure that this is shifted only by a number between 0 and 15 inclusive.
See section 6.10 for a description of underlying type.
There are various ways of ensuring this rule is followed. The simplest is for the right-hand operand to
be a constant (whose value can then be statically checked). Use of an unsigned integer type will ensure
that the operand is non-negative, so then only the upper limit needs to be checked (dynamically at
run-time or by review). Otherwise both limits will need to be checked.
u8a = (uint8_t) (u8a << 7);
u8a = (uint8_t) (u8a << 9);
u16a = (uint16_t) ((uint16_t) u8a << 9);
/* compliant
*/
/* not compliant */
/* compliant
*/
Applying the unary minus operator to an expression of type unsigned int or unsigned long generates a
result of type unsigned int or unsigned long respectively and is not a meaningful operation. Applying
unary minus to an operand of smaller unsigned integer type may generate a meaningful signed result due
to integral promotion, but this is not good practice.
See section 6.10 for a description of underlying type.
54
6. Rules (continued)
Rule 12.10 (required):
Use of the comma operator is generally detrimental to the readability of code, and the same effect can
be achieved by other means.
Rule 12.11 (advisory):
Because unsigned integer expressions do not strictly overflow, but instead wrap around in a modular
way, any constant unsigned integer expressions which in effect overflow will not be detected by the
compiler. Although there may be good reasons at run-time to rely on the modular arithmetic provided by
unsigned integer types, the reasons for using it at compile-time to evaluate a constant expression are less
obvious. Any instance of an unsigned integer constant expression wrapping around is therefore likely to
indicate a programming error.
This rule applies equally to all phases of the translation process. Constant expressions that the compiler
chooses to evaluate at compile time are evaluated in such a way that the results are identical to those that
would be obtained by evaluation on the target with the exception of those appearing in conditional
preprocessing directives. For such directives, the usual rules of arithmetic (see section 6.4 of
ISO 9899:1990 [2]) apply but the int and unsigned int types behave instead as if they were long and
unsigned long respectively.
For example, on a machine with a 16-bit int type and a 32-bit long type:
#define START 0x8000
#define END
0xFFFF
#define LEN
0x8000
#if ((START + LEN) > END)
#error Buffer Overrun /* OK because START and LEN are unsigned long */
#endif
#if (((END - START) - LEN) < 0)
#error Buffer Overrun
/* Not OK: subtraction result wraps around to 0xFFFFFFFF */
#endif
/* contrast the above START + LEN with the following */
if ((START + LEN) > END)
{
error ("Buffer overrun");
/* Not OK: START + LEN wraps around to 0x0000 due to unsigned int
arithmetic */
}
55
6. Rules (continued)
Rule 12.12 (required):
The storage layout used for floating-point values may vary from one compiler to another, and therefore
no floating-point manipulations shall be made which rely directly on the way the values are stored. The
in-built operators and functions, which hide the storage details from the programmer, should be used.
Rule 12.13 (advisory):
The use of increment and decrement operators in combination with other arithmetic operators is not
recommended because:
It introduces additional side effects into a statement with the potential for undefined behaviour
It is safer to use these operations in isolation from any other arithmetic operators.
For example a statement such as the following is not compliant:
u8a = ++u8b + u8c--;
/* Not compliant */
No assignments are permitted in any expression which is considered to have a Boolean value. This
precludes the use of both simple and compound assignment operators in the operands of a
Boolean-valued expression. However, it does not preclude assigning a Boolean value to a variable.
If assignments are required in the operands of a Boolean-valued expression then they must be performed
separately outside of those operands. This helps to avoid getting = and == confused, and assists the
static detection of mistakes.
56
6. Rules (continued)
See Boolean expressions in the glossary.
For example write:
x = y;
if ( x != 0 )
{
foo();
}
and not:
if ( ( x = y ) != 0 )
{
foo();
}
/* Boolean by context */
or even worse:
if ( x = y )
{
foo();
}
Where a data value is to be tested against zero then the test should be made explicit. The exception to
this rule is when data represents a Boolean value, even though in C this will in practice be an integer.
This rule is in the interests of clarity, and makes clear the distinction between integers and logical
values.
For example, if x is an integer, then:
if ( x != 0 )
if ( y )
57
6. Rules (continued)
Rule 13.3 (required):
The inherent nature of floating-point types is such that comparisons of equality will often not evaluate
to true even when they are expected to. In addition the behaviour of such a comparison cannot be
predicted before execution, and may well vary from one implementation to another. For example the
result of the test in the following code is unpredictable:
float32_t x, y;
/* some calculations in here
*/
if ( x == y )
/* not compliant */
{ /* ... */ }
if ( x == 0.0f) /* not compliant */
An indirect test is equally problematic and is also forbidden by this rule, for example:
if ( ( x <= y ) && ( x >= y ) )
{ /* ... */ }
The recommended method for achieving deterministic floating-point comparisons is to write a library
that implements the comparison operations. The library should take into account the floating-point
granularity (FLT_EPSILON) and the magnitude of the numbers being compared. See also Rule 13.4 and
Rule 20.3.
Rule 13.4 (required):
The controlling expression may include a loop counter, whose value is tested to determine termination
of the loop. Floating-point variables shall not be used for this purpose. Rounding and truncation errors
can be propagated through the iterations of the loop, causing significant inaccuracies in the loop
variable, and possibly giving unexpected results when the test is performed. For example the number of
times the loop is performed may vary from one implementation to another, and may be unpredictable.
See also Rule 13.3.
Rule 13.5 (required):
When present, the three expressions of a for statement shall be used only for these purposes:
First expression
Second expression
Shall include testing the loop counter (i), and optionally other loop
control variables (flag)
Third expression
58
6. Rules (continued)
Rule 13.6 (required):
Loop counters shall not be modified in the body of the loop. However other loop control variables
representing logical values may be modified in the loop, for example a flag to indicate that something
has been completed, which is then tested in the for statement.
flag = 1;
for ( i = 0; (i < 5) && (flag == 1); i++ )
{
/* ... */
flag = 0;
/* Compliant - allows early termination of loop */
i = i + 3; /* Not compliant - altering the loop counter
*/
}
If a Boolean operator yields a result that can be proven to be always true or always false, it is
highly likely that there is a programming error.
enum ec {RED, BLUE, GREEN} col;
...
if (u16a < 0)
/*
...
if (u16a <= 0xffff)
/*
...
if (s8a < 130)
/*
...
if ((s8a < 10) && (s8a > 20)) /*
...
if ((s8a < 10) || (s8a > 5)) /*
...
if (col <= GREEN)
/*
...
if (s8a > 10)
{
if (s8a > 5)
/*
{
}
}
59
6. Rules (continued)
6.14 Control flow
Rule 14.1 (required):
This rule refers to code which cannot under any circumstances be reached, and which can be identified
as such at compile-time. Code that can be reached but may never be executed is excluded from the rule
(e.g. defensive programming code).
A portion of code is unreachable if there is no control flow path from the relevant entry point to that code.
For example, unlabelled code following an unconditional control transfer is unreachable:
switch (event)
{
case E_wakeup:
do_wakeup();
break;
do_more();
/* ... */
default:
/* ... */
break;
}
Any statement (other than a null statement) which has no side effect and does not result in a change of
control flow will normally indicate a programming error, and therefore a static check for such statements
shall be performed. For example, the following statements do not necessarily have side effects when
executed:
/* assume uint16_t x;
and
uint16_t i; */
...
x >= 3u;
/* not compliant: x is compared to 3,
and the answer is discarded */
Note that null statement and side effect are defined in ISO 9899:1990 [2] sections 6.6.3 and 5.1.2.3
respectively.
60
6. Rules (continued)
Rule 14.3 (required):
Null statements should not normally be deliberately included, but where they are used they shall appear
on a line by themselves. White-space characters may precede the null statement to preserve indentation.
If a comment follows the null statement then at least one white-space character shall separate the null
statement from the comment. The use of a white-space character to separate the null statement from any
following comment is required on the grounds that it provides an important visual cue to reviewers.
Following this rule enables a static checking tool to warn of null statements appearing on a line with
other text, which would normally indicate a programming error. For example:
while ( ( port & 0x80 ) == 0 )
{
; /* wait for pin - Compliant */
/* wait for pin */ ; /* Not compliant, comment before ; */
;/* wait for pin - Not compliant, no white-space char after ; */
}
These rules are in the interests of good structured programming. One break statement is allowed in a loop
since this allows, for example, for dual outcome loops or for optimal coding.
Rule 14.7 (required):
A function shall have a single point of exit at the end of the function.
[IEC 61508 Part 3 Table B.9]
The statement forming the body of a switch, while, do ... while or for
statement shall be a compound statement.
The statement that forms the body of a switch statement or a while, do ... while or for loop, shall be a
compound statement (enclosed within braces), even if that compound statement contains a single
statement.
61
6. Rules (continued)
For example:
for (i = 0; i < N_ELEMENTS; ++i)
{
buffer[i] = 0;
/* Even a single statement must be in braces */
}
while ( new_data_available )
process_data ();
/* Incorrectly not enclosed in braces */
service_watchdog (); /* Added later but, despite the appearance
(from the indent) it is actually not
part of the body of the while statement,
and is executed only after the loop has
terminated */
Note that the layout for compound statements and their enclosing braces should be determined from the
style guidelines. The above is just an example.
Rule 14.9 (required):
For example:
if ( test1 )
{
x = 1;
/* Even a single statement must be in braces */
}
else if ( test2 )
/* No need for braces in else if
*/
{
x = 0;
/* Single statement must be in braces
*/
}
else
x = 3;
/* This was (incorrectly) not enclosed in braces */
y = 2;
/* This line was added later but, despite the appearance
(from the indent) it is actually not part of the else,
and is executed unconditionally */
Note that the layout for compound statements and their enclosing braces should be determined from the
style guidelines. The above is just an example.
Rule 14.10 (required):
This rule applies whenever an if statement is followed by one or more else if statements; the final else if
shall be followed by an else statement. In the case of a simple if statement then the else statement need
not be included.
62
6. Rules (continued)
The requirement for a final else statement is defensive programming. The else statement should either
take appropriate action or contain a suitable comment as to why no action is taken. This is consistent
with the requirement to have a final default clause in a switch statement (Rule 15.3).
For example this code is a simple if statement:
if ( x < 0 )
{
log_error(3);
x = 0;
}
63
6. Rules (continued)
default-label-clause :
default-label default-clause
default-label:
default :
default-clause:
case-clause
and
statement :
/* labelled_statement removed */
compound_statement
expression_statement
selection_statement
iteration_statement
/* jump_statement removed or just restricted to return depending on other rules */
The following terms are also used within the text of the rules:
switch label
case clause
default clause
switch clause
A switch statement shall only contain switch labels and switch clauses, and no other code.
Rule 15.1 (required):
The scope of a case or default label shall be the compound statement, which is the body of a switch
statement. All case clauses and the default clause shall be at the same scope.
Rule 15.2 (required):
The last statement in every switch clause shall be a break statement, or if the switch clause is a
compound statement, then the last statement in the compound statement shall be a break statement.
Rule 15.3 (required):
The requirement for a final default clause is defensive programming. This clause should either take
appropriate action or contain a suitable comment as to why no action is taken.
64
6. Rules (continued)
Rule 15.4 (required):
For example:
switch (x)
{
uint8_t var;
case 0:
a = b;
break;
case 1:
case 2:
a = c;
if ( a == b )
{
case 3:
}
break;
case 4:
a = b;
case 5:
a = c;
break;
default:
errorflag = 1;
break;
*/
*/
*/
/* executed if x is 1 or 2
*/
*/
*/
*/
*/
*/
*/
65
6. Rules (continued)
6.16 Functions
Rule 16.1 (required):
There are a lot of potential problems with this feature. Users shall not write additional functions that use
a variable number of arguments. This precludes the use of use of stdarg.h, va_arg, va_start and va_end.
Rule 16.2 (required):
This means that recursive function calls cannot be used in safety-related systems. Recursion carries with
it the danger of exceeding available stack space, which can be a serious error. Unless recursion is very
tightly controlled, it is not possible to determine before execution what the worst-case stack usage could
be.
Rule 16.3 (required):
Names shall be given for all the parameters in the function declaration for reasons of compatibility,
clarity and maintainability.
Rule 16.4 (required):
Functions shall be declared with a return type (see Rule 8.2), that type being void if the function does
not return any data. Similarly, if the function has no parameters, the parameter list shall be declared as
void. Thus for example, a function, myfunc, which neither takes parameters nor returns a value would
be declared as:
void myfunc ( void );
This problem is completely avoided by the use of function prototypes see Rule 8.1. This rule is retained
since compilers may not flag this constraint error.
66
6. Rules (continued)
Rule 16.7 (advisory):
This rule leads to greater precision in the definition of the function interface. The const qualification
should be applied to the object pointed to, not to the pointer, since it is the object itself that is being
protected.
For example:
void myfunc( int16_t * param1, const int16_t * param2, int16_t * param3)
/* param1: Addresses an object which is modified - no const
param2: Addresses an object which is not modified - const required
param3: Addresses an object which is not modified - const missing */
{
*param1 = *param2 + *param3;
return;
}
/* data at address param3 has not been changed, but this is not const
therefore not compliant */
All exit paths from a function with non-void return type shall have
an explicit return statement with an expression.
[Undefined 43]
This expression gives the value that the function returns. The absence of a return with an expression
leads to undefined behaviour (and the compiler may not give an error).
Rule 16.9 (required):
then it is not clear if the intent is to test if the address of the function is not NULL or that a call to the
function f() should be made.
67
6. Rules (continued)
Rule 16.10 (required):
A function (whether it is part of the standard library, a third party library or a user defined function) may
provide some means of indicating the occurrence of an error. This may be via an error flag, some
special return value or some other means. Whenever such a mechanism is provided by a function the
calling program shall check for the indication of an error as soon as the function returns.
However, note that the checking of input values to functions is considered a more robust means of error
prevention than trying to detect errors after the function has completed (see Rule 20.3). Note also that
the use of errno (to return error information from functions) is clumsy and should be used with care (see
Rule 20.5).
Addition and subtraction of integers (including increment and decrement) from pointers that do not point
to an array or array element results in undefined behaviour.
Rule 17.2 (required):
Subtraction of pointers only gives well-defined results if the two pointers point (or at least behave as if
they point) into the same array object.
Rule 17.3 (required):
>, >=, <, <= shall not be applied to pointer types except where they
68
6. Rules (continued)
Rule 17.4 (required):
Array indexing is the only acceptable form of pointer arithmetic, because it is clearer and hence less error
prone than pointer manipulation. This rule bans the explicit calculation of pointer values. Array
indexing shall only be applied to objects defined as an array type. Any explicitly calculated pointer value
has the potential to access unintended or invalid memory addresses. Pointers may go out of bounds of
arrays or structures, or may even point to effectively arbitrary locations. See also Rule 21.1.
void my_fn(uint8_t * p1, uint8_t p2[])
{
uint8_t index = 0;
uint8_t * p3;
uint8_t * p4;
*p1 = 0;
p1 ++;
/* not compliant
p1 = p1 + 5; /* not compliant
p1[5] = 0;
/* not compliant
p3 = &p1[5]; /* not compliant
p2[0] = 0;
index ++;
index = index + 5;
p2[index] = 0; /* compliant
p4 = &p2[5];
/* compliant
pointer increment
*/
pointer increment
*/
p1 was not declared as an array */
p1 was not declared as an array */
*/
*/
}
uint8_t a1[16];
uint8_t a2[16];
my_fn(a1, a2);
my_fn(&a1[4], &a2[4]);
uint8_t a[10];
uint8_t * p;
p = a;
*(p+5) = 0; /* not compliant */
p[5] = 0;
/* compliant
*/
69
6. Rules (continued)
Rule 17.5 (advisory):
Use of more than 2 levels of indirection can seriously impair the ability to understand the behaviour of
the code, and should therefore be avoided.
typedef int8_t * INTPTR;
struct s {
int8_t *
s1; /* compliant
*/
int8_t ** s2; /* compliant
*/
int8_t *** s3; /* not compliant */
};
struct s *
ps1; /* compliant
*/
struct s ** ps2; /* compliant
*/
struct s *** ps3; /* not compliant */
int8_t
int8_t
int8_t
int8_t
**
**
**
***
( *pfunc1)();
( **pfunc2)();
(***pfunc3)();
( **pfunc4)();
/*
/*
/*
/*
compliant
compliant
not compliant
not compliant
*/
*/
*/
*/
Explanation of types:
par3 and ptr3 are of type pointer to a pointer to a pointer to int8_t. This is three levels and
is not compliant.
par5 and ptr5 are expanded to a type of const pointer to a const pointer to a
pointer to int8_t. This is three levels and is not compliant.
70
6. Rules (continued)
par6 is of type pointer to pointer to int8_t because arrays are converted to a pointer to the
initial element of the array.
par7 is of type pointer to pointer to pointer to int8_t because arrays are converted to a pointer
to the initial element of the array. This is three levels and is not compliant.
If the address of an automatic object is assigned to another automatic object of larger scope, or to a
static object, or returned from a function then the object containing the address may exist beyond the
time when the original object ceases to exist (and its address becomes invalid).
For example
int8_t * foobar(void)
{
int8_t local_auto;
return (&local_auto); /* not compliant */
}
A complete declaration of the structure or union shall be included within any translation unit that refers
to that structure. See section 6.1.2.5 of ISO 9899:1990 [2] for a full description of incomplete types.
struct tnode * pt;
struct tnode
{
int count;
struct tnode * left;
struct tnode * right;
};
*/
The behaviour is undefined when two objects are created which have some overlap in memory and one
is copied to the other.
71
6. Rules (continued)
Rule 18.3 (required):
This rule refers to the technique of using memory to store some data, and then using the same memory
to store unrelated data at some other time during the execution of the program. Clearly it relies on the
two different pieces of data existing at disjoint periods of the programs execution, and never being
required simultaneously.
This practice is not recommended for safety-related systems as it brings with it a number of dangers. For
example: a program might try to access data of one type from the location when actually it is storing a
value of the other type (e.g. due to an interrupt). The two types of data may align differently in the
storage, and encroach upon other data. Therefore the data may not be correctly initialised every time the
usage switches. The practice is particularly dangerous in concurrent systems.
However it is recognised that sometimes such storage sharing may be required for reasons of efficiency.
Where this is the case it is essential that measures are taken to ensure that the wrong type of data can
never be accessed, that data is always properly initialised and that it is not possible to access parts of
other data (e.g. due to alignment differences). The measures taken shall be documented and justified in
the deviation that is raised against this rule.
This might be achieved by the use of unions, or various other means.
Note that there is no intention in the MISRA-C guidelines to place restrictions on how a compiler
actually translates source code as the user generally has no effective control over this. So for example,
memory allocation within the compiler whether dynamic heap, dynamic stack or static, may vary
significantly with only slight code changes even at the same level of optimisation. Note also that some
optimisation may legitimately take place even when the user makes no specific request for this.
Rule 18.4 (required):
Rule 18.3 prohibits the reuse of memory areas for unrelated purposes. However, even when memory is
being reused for related purposes, there is still a risk that the data may be misinterpreted. Therefore, this
rule prohibits the use of unions for any purpose.
It is recognised nonetheless that there are situations in which the careful use of unions is desirable in
constructing an efficient implementation. In such situations, deviations to this rule are considered
acceptable provided that all relevant implementation-defined behaviour is documented. This might be
achieved in practice by referencing the implementation section of the compiler manuals from the design
documentation. The kinds of implementation behaviour that might be relevant are:
alignment how members of any structures within the union are aligned
endianness whether the most significant byte of a word is stored at the lowest or highest
memory address
bit-order how bits are numbered within bytes and how bits are allocated to bit fields
72
6. Rules (continued)
The use of deviations is acceptable for (a) packing and unpacking of data, for example when sending and
receiving messages, and (b) implementing variant records provided that the variants are differentiated by
a common field. Variant records without a differentiator are not considered suitable for use in any
situation.
the implementation stores words with the most significant byte at the lowest memory address
The code to implement the receipt and packing of the bytes could be:
typedef union {
uint32_t word;
uint8_t bytes[4];
} word_msg_t;
uint32_t read_word_big_endian (void)
{
word_msg_t tmp;
tmp.bytes[0]
tmp.bytes[1]
tmp.bytes[2]
tmp.bytes[3]
=
=
=
=
read_byte();
read_byte();
read_byte();
read_byte();
return (tmp.word);
}
It is worth noting that the body of the routine could be written in a portable manner as follows:
uint32_t read_word_big_endian (void)
{
uint32_t word;
word
word
word
word
=
((uint32_t)read_byte()) << 24;
= word | (((uint32_t)read_byte()) << 16);
= word | (((uint32_t)read_byte()) << 8);
= word | ((uint32_t)read_byte());
return (word);
}
73
6. Rules (continued)
Unfortunately, most compilers produce far less efficient code when faced with the portable
implementation. When high execution speed or low program memory usage is more important than
portability, the implementation using unions might be preferred.
Variant records
Unions are often used to implement variant records. Each variant shares common fields and has
additional fields that are specific to the variant. This example is based on the CAN Calibration Protocol
(CCP), in which each CAN message sent to a CCP client shares two common fields, each of one byte.
Up to 6 additional bytes may follow, the interpretation of which depends on the message type stored in
the first byte.
The assumptions that this particular implementation rely on are:
the alignment and packing rules are such that there is no gap between the uint8_t and uint16_t
members of the structure
In the interests of brevity, only two message types are considered in this example. The code that is
presented here is incomplete and should be viewed merely to illustrate the purpose of variant records and
not as a model implementation of CCP.
/* The fields common to all CCP messages */
typedef struct {
uint8_t msg_type;
uint8_t sequence_no;
} ccp_common_t;
/* CCP connect message */
typedef struct {
ccp_common_t common_part;
uint16_t station_to_connect;
} ccp_connect_t;
/* CCP disconnect message */
typedef struct {
ccp_common_t common_part;
uint8_t disconnect_command;
uint8_t pad;
uint16_t station_to_disconnect;
} ccp_disconnect_t;
74
6. Rules (continued)
/* The variant */
typedef union {
ccp_common_t
common;
ccp_connect_t
connect;
ccp_disconnect_t disconnect;
} ccp_message_t;
void process_ccp_message (ccp_message_t *msg)
{
switch (msg->common.msg_type)
{
case Ccp_connect:
if (MY_STATION == msg->connect.station_to_connect)
{
ccp_connect ();
}
break;
case Ccp_disconnect:
if (MY_STATION == msg->disconnect.station_to_disconnect)
{
if (PERM_DISCONNECT == msg->disconnect.disconnect_command)
{
ccp_disconnect ();
}
}
break;
default:
break; /* ignore unknown commands */
}
}
All the #include statements in a particular code file should be grouped together near the head of the file.
The rule states that the only items which may precede a #include in a file are other preprocessor
directives or comments.
Rule 19.2 (advisory):
If the ', \, ", or /* characters are used between < and > delimiters or the ', \, or /* characters are used
between the " delimiters in a header name preprocessing token, then the behaviour is undefined.
75
6. Rules (continued)
Rule 19.3 (required):
These are the only permitted uses of macros. Storage class specifiers and type qualifiers include
keywords such as extern, static and const. Any other use of #define could lead to unexpected behaviour
when substitution is made, or to very hard-to-read code.
In particular macros shall not be used to define statements or parts of statements except the use of the
do-while construct. Nor shall macros redefine the syntax of the language. All brackets of whatever type
( ) { } [ ] in the macro replacement list shall be balanced.
The do-while-zero construct (see example below) is the only permitted mechanism for having complete
statements in a macro body. The do-while-zero construct is used to wrap a series of one or more
statements and ensure correct behaviour. Note: the semicolon must be omitted from the end of the macro
body.
For example:
/* The following are compliant */
#define PI 3.14159F
/* Constant
#define XSTAL 10000000
/* Constant
#define CLOCK (XSTAL/16)
/* Constant expression
#define PLUS2(X) ((X) + 2)
/* Macro expanding to expression
#define STOR extern
/* storage class specifier
#define INIT(value) { (value), 0, 0} /* braced initialiser
#define READ_TIME_32() \
do { \
DISABLE_INTERRUPTS (); \
time_now = (uint32_t)TIMER_HI << 16; \
time_now = time_now | (uint32_t)TIMER_LO; \
ENABLE_INTERRUPTS (); \
} while (0)
/* example of do-while-zero
*/
*/
*/
*/
*/
*/
*/
76
6. Rules (continued)
Rule 19.5 (required):
While it is legal C to place #define or #undef directives anywhere in a code file, placing them inside
blocks is misleading as it implies a scope restricted to that block, which is not the case.
Normally, #define directives will be placed near the start of a file, before the first function definition.
Normally, #undef directives will not be needed (see Rule 19.6).
Rule 19.6 (required):
#undef should not normally be needed. Its use can lead to confusion with respect to the existence or
meaning of a macro when it is used in the code.
Rule 19.7 (advisory):
While macros can provide a speed advantage over functions, functions provide a safer and more robust
mechanism. This is particularly true with respect to the type checking of parameters, and the problem of
function-like macros potentially evaluating parameters multiple times.
Rule 19.8 (required):
This is a constraint error, but preprocessors have been known to ignore this problem. Each argument in
a function-like macro must consist of at least one preprocessing token otherwise the behaviour is
undefined.
Rule 19.9 (required):
If any of the arguments act like preprocessor directives, the behaviour when macro substitution is made
can be unpredictable.
Rule 19.10 (required):
Within a definition of a function-like macro, the arguments shall be enclosed in parentheses. For
example define an abs function using:
#define abs(x) (((x) >= 0) ? (x) : -(x))
and not:
#define abs(x) ((x >= 0) ? x : -x)
77
6. Rules (continued)
If this rule is not adhered to then when the preprocessor substitutes the macro into the code the operator
precedence may not give the desired results.
Consider what happens if the second, incorrect, definition is substituted into the expression:
z = abs( a - b );
giving:
z = ((a - b >= 0) ? a - b : -a - b);
The sub-expression -a - b is equivalent to (-a)-b rather than -(a-b) as intended. Putting all the
parameters in parentheses in the macro definition avoids this problem.
Rule 19.11 (required):
If an attempt is made to use an identifier in a preprocessor directive, and that identifier has not been
defined, the preprocessor will sometimes not give any warning but will assume the value zero. #ifdef,
#ifndef and defined() are provided to test the existence of a macro, and are therefore excluded.
For example:
#if x < 0
Consideration should be given to the use of a #ifdef test before an identifier is used.
Note that preprocessing identifiers may be defined either by use of #define directives or by options
specified at compiler invocation. However the use of the #define directive is preferred.
Rule 19.12 (required):
There is an issue of unspecified order of evaluation associated with the # and ## preprocessor operators.
To avoid this problem only one occurrence of either operator shall be used in any single macro
definition (i.e. one #, or one ## or neither).
Rule 19.13 (advisory):
There is an issue of unspecified order of evaluation associated with the # and ## preprocessor operators.
Compilers have been inconsistent in the implementation of these operators. To avoid these problems do
not use them.
78
6. Rules (continued)
Rule 19.14 (required):
The only two permissible forms for the defined preprocessor operator are:
defined ( identifier )
defined identifier
Any other form leads to undefined behaviour, for example:
#if defined(X > Y)
Generation of the token defined during expansion of a #if or #elif preprocessing directive also leads to
undefined behaviour and shall be avoided, for example:
#define DEFINED defined
#if DEFINED(X)
/* not compliant - undefined behaviour */
When a translation unit contains a complex hierarchy of nested header files it can happen that a
particular header file is included more than once. This can be, at best, a source of confusion. If it leads
to multiple or conflicting definitions, the result can be undefined or erroneous behaviour.
Multiple inclusions of a header file can sometimes be avoided by careful design. If this is not possible,
a mechanism must be in place to prevent the file contents from being included more than once. A common approach is to associate a macro with each file; the macro is defined when the file is included for
the first time and used subsequently when the file is included again to exclude the contents of the file.
For example a file called ahdr.h might be structured as follows:
#ifndef AHDR_H
#define AHDR_H
/* The following lines will be excluded by the
preprocessor if the file is included more
than once */
...
#endif
79
6. Rules (continued)
Alternatively, the following may be used.
#ifdef AHDR_H
#error Header file is already included
#else
#define AHDR_H
/* The following lines will be excluded by the
preprocessor if the file is included more
than once */
...
#endif
When a section of source code is excluded by preprocessor directives, the content of each excluded
statement is ignored until a #else, #elif or #endif directive is encountered (depending on the context). If
one of these excluded directives is badly formed, it may be ignored without warning by a compiler with
unfortunate consequences.
The requirement of this rule is that all preprocessor directives shall be syntactically valid even when they
occur within an excluded block of code.
In particular, ensure that #else and #endif directives are not followed by any characters other than
white-space. Compilers are not always consistent in enforcing this ISO requirement.
#define AAA 2
...
int foo(void)
{
int x = 0;
...
#ifndef AAA
x = 1;
#else1
x = AAA;
#endif
...
return x;
}
/* Not compliant */
All #else, #elif and #endif preprocessor directives shall reside in the
same file as the #if or #ifdef directive to which they are related.
80
6. Rules (continued)
When the inclusion and exclusion of blocks of statements is controlled by a series of preprocessor
directives, confusion can arise if all of the relevant directives do not occur within one file. This rule
requires that all preprocessor directives in a sequence of the form #if / #ifdef ... #elif ... #else ... #endif
shall reside in the same file. Observance of this rule preserves good code structure and avoids
maintenance problems.
Notice that this does not preclude the possibility that such directives may exist within included files so
long as all directives that relate to the same sequence are located in one file.
file.c
#define A
...
#ifdef A
...
#include "file1.h"
#
#endif
...
#if 1
#include "file2.h"
...
EOF
file1.h
#if 1
...
#endif
EOF
/* Compliant */
file2.h
...
#endif
/* Not compliant */
It is generally bad practice to #undef a macro which is defined in the standard library. It is also bad
practice to #define a macro name which is a C reserved identifier or C keyword which is the name of
any macro, object or function in the standard library. For example, there are some specific reserved
words and function names which are known to give rise to undefined behaviour if they are redefined or
undefined, including defined, _ _LINE_ _, _ _FILE_ _, _ _DATE_ _, _ _TIME_ _, _ _STDC_ _, errno
and assert.
See also Rule 19.6 regarding the use of #undef.
81
6. Rules (continued)
ISO C reserved identifiers are documented in sections 7.1.3 and 7.13 of ISO 9899:1990 [2] and should
also be documented by the compiler writer. Generally, all identifiers that begin with the underscore
character are reserved.
Rule 20.2 (required):
Where new versions of standard library macros, objects or functions are used by the programmer (e.g.
enhanced functionality or checks of input values) the modified macro, object or function shall have a
new name. This is to avoid any confusion as to whether a standard macro, object or function is being
used or whether a modified version of that function is being used. So, for example, if a new version of
the sqrt function is written to check that the input is not negative, the new function shall not be named
sqrt, but shall be given a new name.
Rule 20.3 (required):
Many functions in the standard C libraries are not required by the ISO standard [2] to check the
validity of parameters passed to them. Even where checking is required by the standard, or where
compiler writers claim to check parameters, there is no guarantee that adequate checking will take place.
Therefore the programmer shall provide appropriate checks of input values for all library functions
which have a restricted input domain (standard libraries, other bought in libraries, and in-house
libraries).
Examples of functions that have a restricted domain and need checking are:
toupper and tolower: some implementations can produce unexpected results when the function
toupper is passed a parameter which is not a lower case letter (and similarly for tolower)
the character testing functions in ctype.h exhibit undefined behaviour if passed invalid values
the abs function applied to the most negative integer gives undefined behaviour
Although most of the math library functions in math.h define allowed input domains, the values they
return when a domain error occurs may vary from one compiler to another. Therefore pre-checking the
validity of the input values is particularly important for these functions.
The programmer should identify any domain constraints which should sensibly apply to a function being
used (which may or may not be documented in the standard), and provide appropriate checks that the
input value(s) lies within this domain. Of course the value may be restricted further, if required, by
knowledge of what the parameter represents and what constitutes a sensible range of values for the
82
6. Rules (continued)
There are a number of ways in which the requirements of this rule might be satisfied, including the
following:
Design checks into the function. This is particularly applicable for in-house designed libraries,
though it could apply to bought-in libraries if the supplier can demonstrate that they have built
in the checks
Produce wrapped versions of functions, that perform the checks then call the original
function
Demonstrate statically that the input parameters can never take invalid values
Note that when checking a floating-point parameter to a function, that has a singularity at zero, it may
be appropriate to perform a test of equality to zero. This is an acceptable exception to Rule 13.3 without
the need to raise a deviation. However it will usually still be necessary to test to a tolerance around zero
(or any other singularity) if the magnitude of the value of the function tends to infinity as the parameter
tends to zero, so as to prevent overflow occurring.
Rule 20.4 (required):
This precludes the use of the functions calloc, malloc, realloc and free.
There is a whole range of unspecified, undefined and implementation-defined behaviour associated with
dynamic memory allocation, as well as a number of other potential pitfalls. Dynamic heap memory
allocation may lead to memory leaks, data inconsistency, memory exhaustion, non-deterministic
behaviour.
Note that some implementations may use dynamic heap memory allocation to implement other functions
(for example functions in the library string.h). If this is the case then these functions shall also be
avoided.
Rule 20.5 (required):
errno is a facility of C, which in theory should be useful, but which in practice is poorly defined by the
standard. A non zero value may or may not indicate that a problem has occurred; as a result it shall not
be used. Even for those functions for which the behaviour of errno is well defined, it is preferable to
check the values of inputs before calling the function rather than rely on using errno to trap errors (see
Rule 16.10).
Rule 20.6 (required):
Use of this macro can lead to undefined behaviour when the types of the operands are incompatible or
when bit fields are used.
83
6. Rules (continued)
Rule 20.7 (required):
The setjmp macro and the longjmp function shall not be used.
[Unspecified 14; Undefined 6467, Koenig 74]
setjmp and longjmp allow the normal function call mechanisms to be bypassed, and shall not be used.
Rule 20.8 (required):
This includes file and I/O functions fgetpos, fopen, ftell, gets, perror, remove, rename, and ungetc.
Streams and file I/O have a large number of unspecified, undefined and implementation-defined
behaviours associated with them. It is assumed within this document that they will not normally be
needed in production code in embedded systems.
If any of the features of stdio.h need to be used in production code, then the issues associated with the
feature need to be understood.
Rule 20.10 (required):
The library functions atof, atoi and atol from library <stdlib.h> shall
not be used.
[Undefined 90]
These functions have undefined behaviour associated with them when the string cannot be converted.
Rule 20.11 (required):
The library functions abort, exit, getenv and system from library
<stdlib.h> shall not be used.
[Undefined 93; Implementation 7073]
These functions will not normally be required in an embedded system, which does not normally need to
communicate with an environment. If the functions are found necessary in an application, then it is
essential to check on the implementation-defined behaviour of the function in the environment in
question.
Rule 20.12 (required):
Includes time, strftime. This library is associated with clock times. Various aspects are implementation
dependent or unspecified, such as the formats of times. If any of the facilities of time.h are used then the
exact implementation for the compiler being used must be determined, and a deviation raised.
84
6. Rules (continued)
6.21 Run-time failures
Rule 21.1 (required):
Run-time checking is an issue, which is not specific to C, but it is an issue which C programmers need
to pay special attention to. This is because the C language is weak in its provision of any run-time
checking. C implementations are not required to perform many of the dynamic checks that are necessary
for robust software. It is therefore an issue that C programmers need to consider carefully, adding
dynamic checks to code wherever there is potential for run-time errors to occur.
Where expressions consist only of values within a well-defined range, a run-time check may not be
necessary, provided it can be demonstrated that for all values within the defined range the exception
cannot occur. Such a demonstration, if used, should be documented along with the assumptions on which
it depends. However if adopting this approach, be very careful about subsequent modifications of the
code which may invalidate the assumptions, or of the assumptions changing for any other reason.
The following notes give some guidance on areas where consideration needs to be given to the provision
of dynamic checks.
arithmetic errors
This includes errors occurring in the evaluation of expressions, such as overflow, underflow,
divide by zero or loss of significant bits through shifting.
In considering integer overflow, note that unsigned integer calculations do not strictly overflow
(producing undefined values), but the values wrap around (producing defined, but possibly
wrong, values).
pointer arithmetic
Ensure that when an address is calculated dynamically the computed address is reasonable and
points somewhere meaningful. In particular it should be ensured that if a pointer points within
a structure or array, then when the pointer has been incremented or otherwise altered it still
points to the same structure or array. See restrictions on pointer arithmetic Rules 17.1, 17.2
and 17.4.
function parameters
See Rule 20.3.
85
6. Rules (continued)
pointer dereferencing
Where a function returns a pointer and that pointer is subsequently de-referenced the program
should first check that the pointer is not NULL. Within a function, it is relatively
straightforward to reason about which pointers may or may not hold NULL values. Across
function boundaries, especially when calling functions defined in other source files or libraries,
it is much more difficult.
/* Given a pointer to a message, check the message header and return
* a pointer to the body of the message or NULL if the message is
* invalid. */
const char_t *msg_body (const char_t *msg)
{
const char_t *body = NULL;
if (msg != NULL)
{
if (msg_header_valid (msg))
{
body = &msg[MSG_HEADER_SIZE];
}
}
return (body);
}
...
char_t msg_buffer[MAX_MSG_SIZE];
const char_t *payload;
...
payload = msg_body (msg_buffer);
if (payload != NULL)
{
/* process the message payload */
}
The techniques that will be employed to minimise run-time failures should be planned and documented,
e.g. in design standards, test plans, static analysis configuration files, code review checklists.
86
7. References
7. References
[1]
MISRA Guidelines for the Use of the C Language In Vehicle Based Software,
ISBN 0-9524156-9-0, Motor Industry Research Association, Nuneaton, April 1998
[2]
[3]
Hatton L., Safer C - Developing Software for High-integrity and Safety-critical Systems,
ISBN 0-07-707640-0, McGraw-Hill, 1994
[4]
[5]
[6]
[7]
[8]
[9]
[10] CRR80, The Use of Commercial Off-the-Shelf (COTS) Software in Safety Related Applications,
ISBN 0-7176-0984-7, HSE Books
[11] ISO 9001:2000, Quality management systems Requirements, International Organization for
Standardization, 2000
[12] ISO 90003:2004, Software engineering Guidelines for the application of ISO 9001:2000 to
computer software, International Organization for Standardization, 2004
[13] The TickIT Guide, Using ISO 9001:2000 for Software Quality Management System
Construction, Certification and Continual Improvement, Issue 5,
British Standards Institution, 2001
[14] Straker D., C Style: Standards and Guidelines, ISBN 0-13-116898-3, Prentice Hall 1991
[15] Fenton N.E. and Pfleeger S.L., Software Metrics: A Rigorous and Practical Approach,
2nd Edition, ISBN 0-534-95429-1, PWS, 1998
[16] MISRA Report 5 Software Metrics, Motor Industry Research Association, Nuneaton,
February 1995
[17] MISRA Report 6 Verification and Validation, Motor Industry Research Association, Nuneaton,
February 1995
[18] Kernighan B.W., Ritchie D.M., The C programming language, 2nd edition,
ISBN 0-13-110362-8, Prentice Hall, 1988 (note: The 1st edition is not a suitable reference
document as it does not describe ANSI/ISO C)
87
7. References (continued)
[19] Koenig A., C Traps and Pitfalls, ISBN 0-201-17928-8, Addison-Wesley, 1988
[20] IEC 61508, Functional safety of electrical/electronic/programmable electronic safety-related
systems, International Electrotechnical Commission, in 7 parts published between
1998 and 2000
[21] ANSI/IEEE Std 754, IEEE Standard for Binary Floating-Point Arithmetic, 1985
[22] ISO/IEC 10646:2003, Information technology Universal Multiple-Octet Coded Character
Set (UCS), International Organization for Standardization, 2003
88
Appendix A
Appendix A: Summary of rules
This appendix gives a summary of all the rules in section 6 of this document.
Environment
1.1 (req)
1.2 (req)
1.3 (req)
Multiple compilers and/or languages shall only be used if there is a common defined
interface standard for object code to which the languages/compilers/assemblers conform.
1.4 (req)
The compiler/linker shall be checked to ensure that 31 character significance and case
sensitivity are supported for external identifiers.
1.5 (adv)
Language extensions
2.1 (req)
2.2 (req)
2.3 (req)
2.4 (adv)
Documentation
3.1 (req)
3.2 (req)
3.3 (adv)
3.4 (req)
3.5 (req)
3.6 (req)
All libraries used in production code shall be written to comply with the provisions of this
document, and shall have been subject to appropriate validation.
89
Appendix A (continued)
Character sets
4.1 (req)
Only those escape sequences that are defined in the ISO C standard shall be used.
4.2 (req)
Identifiers
5.1 (req)
Identifiers (internal and external) shall not rely on the significance of more than 31
characters.
5.2 (req)
Identifiers in an inner scope shall not use the same name as an identifier in an outer
scope, and therefore hide that identifier.
5.3 (req)
5.4 (req)
5.5 (adv)
5.6 (adv)
No identifier in one name space should have the same spelling as an identifier in another
name space, with the exception of structure and union member names.
5.7 (adv)
Types
6.1 (req)
The plain char type shall be used only for storage and use of character values.
6.2 (req)
signed and unsigned char type shall be used only for the storage and use of numeric
values.
6.3 (adv)
typedefs that indicate size and signedness should be used in place of the basic types.
6.4 (req)
Bit fields shall only be defined to be of type unsigned int or signed int.
6.5 (req)
Constants
7.1 (req)
Octal constants (other than zero) and octal escape sequences shall not be used.
90
Appendix A (continued)
Declarations and definitions
8.1 (req)
Functions shall have prototype declarations and the prototype shall be visible at both the
function definition and call.
8.2 (req)
Whenever an object or function is declared or defined, its type shall be explicitly stated.
8.3 (req)
For each function parameter the type given in the declaration and definition shall be
identical, and the return types shall also be identical.
8.4 (req)
If objects or functions are declared more than once their types shall be compatible.
8.5 (req)
8.6 (req)
8.7 (req)
Objects shall be defined at block scope if they are only accessed from within a single
function.
8.8 (req)
An external object or function shall be declared in one and only one file.
8.9 (req)
An identifier with external linkage shall have exactly one external definition.
8.10 (req)
All declarations and definitions of objects or functions at file scope shall have internal
linkage unless external linkage is required.
8.11 (req)
The static storage class specifier shall be used in definitions and declarations of objects
and functions that have internal linkage.
8.12 (req)
When an array is declared with external linkage, its size shall be stated explicitly or
defined implicitly by initialisation.
Initialisation
9.1 (req)
All automatic variables shall have been assigned a value before being used.
9.2 (req)
Braces shall be used to indicate and match the structure in the non-zero initialisation of
arrays and structures.
9.3 (req)
In an enumerator list, the = construct shall not be used to explicitly initialise members
other than the first, unless all items are explicitly initialised.
91
Appendix A (continued)
Arithmetic type conversions
10.1 (req)
The value of an expression of integer type shall not be implicitly converted to a different
underlying type if:
a) it is not a conversion to a wider integer type of the same signedness, or
b) the expression is complex, or
c) the expression is not constant and is a function argument, or
d) the expression is not constant and is a return expression.
10.2 (req)
The value of an expression of floating type shall not be implicitly converted to a different
type if:
a) it is not a conversion to a wider floating type, or
b) the expression is complex, or
c) the expression is a function argument, or
d) the expression is a return expression.
10.3 (req)
The value of a complex expression of integer type may only be cast to a type that is
narrower and of the same signedness as the underlying type of the expression.
10.4 (req)
The value of a complex expression of floating type may only be cast to a narrower
floating type.
10.5 (req)
If the bitwise operators ~ and << are applied to an operand of underlying type unsigned
char or unsigned short, the result shall be immediately cast to the underlying type of the
operand.
Conversions shall not be performed between a pointer to a function and any type other
than an integral type.
11.2 (req)
Conversions shall not be performed between a pointer to object and any type other than
an integral type, another pointer to object type or a pointer to void.
11.3 (adv)
A cast should not be performed between a pointer type and an integral type.
11.4 (adv)
A cast should not be performed between a pointer to object type and a different pointer to
object type.
11.5 (req)
A cast shall not be performed that removes any const or volatile qualification from the
type addressed by a pointer.
92
Appendix A (continued)
Expressions
12.1 (adv)
12.2 (req)
The value of an expression shall be the same under any order of evaluation that the
standard permits.
12.3 (req)
The sizeof operator shall not be used on expressions that contain side effects.
12.4 (req)
The right-hand operand of a logical && or || operator shall not contain side effects.
12.5 (req)
12.6 (adv)
12.7 (req)
Bitwise operators shall not be applied to operands whose underlying type is signed.
12.8 (req)
The right-hand operand of a shift operator shall lie between zero and one less than the
width in bits of the underlying type of the left-hand operand.
12.9 (req)
The unary minus operator shall not be applied to an expression whose underlying type is
unsigned.
Assignment operators shall not be used in expressions that yield a Boolean value.
13.2 (adv)
Tests of a value against zero should be made explicit, unless the operand is effectively
Boolean.
13.3 (req)
13.4 (req)
The controlling expression of a for statement shall not contain any objects of floating
type.
13.5 (req)
The three expressions of a for statement shall be concerned only with loop control.
13.6 (req)
Numeric variables being used within a for loop for iteration counting shall not be
modified in the body of the loop.
13.7 (req)
93
Appendix A (continued)
Control flow
14.1 (req)
14.2 (req)
14.3 (req)
Before preprocessing, a null statement shall only occur on a line by itself; it may be
followed by a comment provided that the first character following the null statement is a
white-space character.
14.4 (req)
14.5 (req)
14.6 (req)
For any iteration statement there shall be at most one break statement used for loop
termination.
14.7 (req)
A function shall have a single point of exit at the end of the function.
14.8 (req)
The statement forming the body of a switch, while, do ... while or for statement be a
compound statement.
14.9 (req)
14.10 (req) All if ... else if constructs shall be terminated with an else clause.
Switch statements
15.1 (req)
A switch label shall only be used when the most closely-enclosing compound statement is
the body of a switch statement.
15.2 (req)
15.3 (req)
15.4 (req)
15.5 (req)
94
Appendix A (continued)
Functions
16.1 (req)
16.2 (req)
16.3 (req)
Identifiers shall be given for all of the parameters in a function prototype declaration.
16.4 (req)
The identifiers used in the declaration and definition of a function shall be identical.
16.5 (req)
16.6 (req)
The number of arguments passed to a function shall match the number of parameters.
16.7 (adv)
16.8 (req)
All exit paths from a function with non-void return type shall have an explicit return
statement with an expression.
16.9 (req)
A function identifier shall only be used with either a preceding &, or with a parenthesised
parameter list, which may be empty.
16.10 (req) If a function returns error information, then that error information shall be tested.
Pointer arithmetic shall only be applied to pointers that address an array or array element.
17.2 (req)
Pointer subtraction shall only be applied to pointers that address elements of the same
array.
17.3 (req)
>, >=, <, <= shall not be applied to pointer types except where they point to the same
array.
17.4 (req)
17.5 (adv)
The declaration of objects should contain no more than 2 levels of pointer indirection.
17.6 (req)
The address of an object with automatic storage shall not be assigned to another object
that may persist after the first object has ceased to exist.
95
Appendix A (continued)
Structures and unions
18.1 (req)
All structure or union types shall be complete at the end of a translation unit.
18.2 (req)
18.3 (req)
18.4 (req)
Preprocessing directives
19.1 (adv)
19.2 (adv)
Non-standard characters should not occur in header file names in #include directives.
19.3 (req)
19.4 (req)
19.5 (req)
19.6 (req)
19.7 (adv)
19.8 (req)
19.9 (req)
Arguments to a function-like macro shall not contain tokens that look like preprocessing
directives.
19.10 (req) In the definition of a function-like macro each instance of a parameter shall be enclosed
in parentheses unless it is used as the operand of # or ##.
19.11 (req) All macro identifiers in preprocessor directives shall be defined before use, except in
#ifdef and #ifndef preprocessor directives and the defined() operator.
19.12 (req) There shall be at most one occurrence of the # or ## preprocessor operators in a single
macro definition.
19.13 (adv) The # and ## preprocessor operators should not be used.
19.14 (req) The defined preprocessor operator shall only be used in one of the two standard forms.
19.15 (req) Precautions shall be taken in order to prevent the contents of a header file being included
twice.
19.16 (req) Preprocessing directives shall be syntactically meaningful even when excluded by the
preprocessor.
19.17 (req) All #else, #elif and #endif preprocessor directives shall reside in the same file as the #if or
#ifdef directive to which they are related.
96
Appendix A (continued)
Standard libraries
20.1 (req)
Reserved identifiers, macros and functions in the standard library, shall not be defined,
redefined or undefined.
20.2 (req)
The names of standard library macros, objects and functions shall not be reused.
20.3 (req)
20.4 (req)
20.5 (req)
20.6 (req)
20.7 (req)
The setjmp macro and the longjmp function shall not be used.
20.8 (req)
20.9 (req)
20.10 (req) The library functions atof, atoi and atol from library <stdlib.h> shall not be used.
20.11 (req) The library functions abort, exit, getenv and system from library <stdlib.h> shall not be
used.
20.12 (req) The time handling functions of library <time.h> shall not be used.
Run-time failures
21.1 (req)
Minimisation of run-time failures shall be ensured by the use of at least one of:
a) static analysis tools/techniques;
b) dynamic analysis tools/techniques;
c) explicit coding of checks to handle run-time faults.
97
Appendix B
Appendix B: MISRA-C:1998 to
MISRA-C:2004 rule mapping
MISRA-C:
1998
MISRA-C:
2004
MISRA-C:
2004 Rule
1 (req)
1.1 (req)
1 (req)
1.2 (req)
1 (req)
2.2 (req)
1 (req)
3.1 (req)
2 (adv)
1.3 (req)
3 (adv)
2.1 (req)
4 (adv)
21.1 (req)
5 (req)
4.1 (req)
Only those escape sequences that are defined in the ISO C standard shall
be used.
6 (req)
3.2 (req)
7 (req)
4.2 (req)
8 (req)
Rescinded
9 (req)
2.3 (req)
10 (adv)
2.4 (adv)
11 (req)
1.4 (req)
11 (req)
5.1 (req)
Identifiers (internal and external) shall not rely on the significance of more
than 31 characters.
12 (adv)
5.5 (adv)
12 (adv)
5.6 (adv)
12 (adv)
5.7 (adv)
98
Appendix B (continued)
MISRA-C:
1998
MISRA-C:
2004
MISRA-C:
2004 Rule
13(adv)
6.3 (adv)
typedefs that indicate size and signedness should be used in place of the
basic types.
14 (req)
6.1 (req)
The plain char type shall be used only for storage and use of character
values.
14 (req)
6.2 (req)
signed and unsigned char type shall be used only for the storage and use
of numeric values.
15 (adv)
1.5 (adv)
16 (req)
12.12 (req)
17 (req)
5.3 (req)
18 (adv)
19 (req)
Rescinded
7.1 (req)
20 (req)
Octal constants (other than zero) and octal escape sequences shall not be
used.
Rescinded
21 (req)
5.2 (req)
Identifiers in an inner scope shall not use the same name as an identifier in
an outer scope, and therefore hide that identifier.
22 (adv)
8.7 (req)
Objects shall be defined at block scope if they are only accessed from
within a single function.
23 (adv)
8.10 (req)
24 (req)
8.11 (req)
25 (req)
8.9 (req)
26 (req)
8.4 (req)
If objects or functions are declared more than once their types shall be
compatible.
27 (adv)
8.8 (req)
An external object or function shall be declared in one and only one file.
28 (adv)
Rescinded
29 (req)
5.4 (req)
30 (req)
9.1 (req)
All automatic variables shall have been assigned a value before being
used.
99
Appendix B (continued)
MISRA-C:
1998
MISRA-C:
2004
MISRA-C:
2004 Rule
31 (req)
9.2 (req)
Braces shall be used to indicate and match the structure in the non-zero
initialisation of arrays and structures.
32 (req)
9.3 (req)
33 (req)
12.4 (req)
34 (req)
12.5 (req)
35 (req)
13.1 (req)
36 (adv)
12.6 (adv)
37 (req)
10.5 (req)
37 (req)
12.7 (req)
38 (req)
12.8 (req)
The right-hand operand of a shift operator shall lie between zero and one
less than the width in bits of the underlying type of the left-hand operand.
39 (req)
12.9 (req)
40 (adv)
12.3 (req)
The sizeof operator shall not be used on expressions that contain side
effects.
41 (adv)
3.3 (adv)
42 (req)
12.10 (req)
43 (req)
10.1 (req)
44 (adv)
Rescinded
100
Appendix B (continued)
MISRA-C:
1998
MISRA-C:
2004
MISRA-C:
2004 Rule
45 (req)
11.1 (req)
45 (req)
11.2 (req)
45 (req)
11.3 (adv)
45 (req)
11.4 (adv)
45 (req)
11.5 (req)
46 (req)
12.2 (req)
The value of an expression shall be the same under any order of evaluation
that the standard permits.
47 (adv)
12.1 (adv)
48 (adv)
10.4 (req)
49 (adv)
13.2 (adv)
Tests of a value against zero should be made explicit, unless the operand is
effectively Boolean.
50 (req)
13.3 (req)
51 (adv)
12.11 (adv)
52 (req)
14.1 (req)
53 (req)
14.2 (req)
54 (req)
14.3 (req)
55 (adv)
Rescinded
56 (req)
14.4 (req)
57 (req)
14.5 (req)
58 (req)
Rescinded
101
Appendix B (continued)
MISRA-C:
1998
MISRA-C:
2004
MISRA-C:
2004 Rule
59 (req)
14.8 (req)
The statement forming the body of a switch, while, do ... while or for
statement shall be a compound statement.
59 (req)
14.9 (req)
60 (adv)
14.10 (req)
61 (req)
15.1 (req)
61 (req)
15.2 (req)
62 (req)
15.3 (req)
63 (adv)
15.4 (req)
64 (req)
15.5 (req)
65 (req)
13.4 (req)
The controlling expression of a for statement shall not contain any objects
of floating type.
66 (adv)
13.5 (req)
The three expressions of a for statement shall be concerned only with loop
control.
67 (adv)
13.6 (req)
Numeric variables being used within a for loop for iteration counting shall
not be modified in the body of the loop.
68 (req)
8.6 (req)
69 (req)
16.1 (req)
70 (req)
16.2 (req)
71 (req)
8.1 (req)
72 (req)
8.3 (req)
For each function parameter the type given in the declaration and
definition shall be identical, and the return types shall also be identical.
73 (req)
16.3 (req)
74 (req)
16.4 (req)
75 (req)
8.2 (req)
102
Appendix B (continued)
MISRA-C:
1998
MISRA-C:
2004
MISRA-C:
2004 Rule
76 (req)
16.5 (req)
77 (req)
10.2 (req)
78 (req)
16.6 (req)
79 (req)
Rescinded
80 (req)
Rescinded
81 (adv)
16.7 (adv)
82 (adv)
14.7 (req)
A function shall have a single point of exit at the end of the function.
83 (req)
16.8 (req)
All exit paths from a function with non-void return type shall have an
explicit return statement with an expression.
84 (req)
Rescinded
85 (adv)
16.9 (req)
A function identifier shall only be used with either a preceding &, or with
a parenthesised parameter list, which may be empty.
86 (adv)
16.10 (req)
87 (req)
8.5 (req)
87 (req)
19.1 (adv)
88 (req)
19.2 (adv)
89 (req)
19.3 (req)
90 (req)
19.4 (req)
91 (req)
19.5 (req)
92 (adv)
19.6 (req)
103
Appendix B (continued)
MISRA-C:
1998
MISRA-C:
2004
MISRA-C:
2004 Rule
93 (adv)
19.7 (adv)
94 (req)
19.8(req)
95 (req)
19.9 (req)
Arguments to a function-like macro shall not contain tokens that look like
preprocessing directives.
96 (req)
19.10 (req)
97 (adv)
19.11 (req)
98 (req)
19.12 (req)
98 (req)
19.13 (adv)
99 (req)
3.4 (req)
100 (req)
19.14 (req)
The defined preprocessor operator shall only be used in one of the two
standard forms.
101 (adv)
17.1 (req)
101 (adv)
17.2 (req)
101 (adv)
17.4 (req)
102 (adv)
17.5 (adv)
103 (req)
17.3 (req)
>, >=, <, <= shall not be applied to pointer types except where they
Rescinded
105 (req)
Rescinded
106 (req)
17.6 (req)
107 (req)
108 (req)
18.1 (req)
109 (req)
18.2 (req)
104
Appendix B (continued)
MISRA-C:
1998
MISRA-C:
2004
MISRA-C:
2004 Rule
109 (req)
18.3 (req)
110 (req)
18.4 (req)
111 (req)
6.4 (req)
Bit fields shall only be defined to be of type unsigned int or signed int.
112 (req)
6.5 (req)
113 (req)
Rescinded.
114 (req)
20.1 (req)
Reserved identifiers, macros and functions in the standard library, shall not
be defined, redefined or undefined.
115 (req)
20.2 (req)
The names of standard library macros, objects and functions shall not be
reused.
116 (req)
3.6 (req)
All libraries used in production code shall be written to comply with the
provisions of this document, and shall have been subject to appropriate
validation.
117 (req)
20.3 (req)
118 (req)
20.4 (req)
119 (req)
20.5 (req)
120 (req)
20.6 (req)
121 (req)
Rescinded
122 (req)
20.7 (req)
The setjmp macro and the longjmp function shall not be used.
123 (req)
20.8 (req)
124 (req)
20.9 (req)
125 (req)
20.10 (req)
The library functions atof, atoi and atol from library <stdlib.h> shall not
be used.
126 (req)
20.11 (req)
The library functions abort, exit, getenv and system from library
<stdlib.h> shall not be used.
127 (req)
20.12 (req)
105
Appendix C
Appendix C: MISRA-C:1998 Rescinded rules
Rule 8 (rescinded):
Rule 18 (rescinded):
Rule 20 (rescinded):
Rule 28 (rescinded):
Rule 44 (rescinded):
Rule 55 (rescinded):
Rule 58 (rescinded):
Rule 79 (rescinded):
Rule 80 (rescinded):
Rule 84 (rescinded):
For functions with void return type, return statements shall not
have an expression.
106
Appendix D
Appendix D: Cross references to the ISO standard
This appendix gives cross references between the rules given in this document and the sections of
ISO 9899 [2].
ISO ref
Rule
ISO ref
Rule
ISO ref
1.4
1.5
2.2
2.3
2.4
3.3
3.4
3.5
4.1
4.2
5.1
5.2
5.3
5.4
5.5
5.6
5.7
6.1
6.2
6.3
8.2
8.3
8.4
8.5
8.6
8.7
8.8
8.9
8.10
7.1
8.1
6.1.3.2
6.3.2.2, 6.5.4.3
9.1
9.2
9.3
10.1
10.2
10.3
10.4
10.5
10.6
11.1
11.2
11.3
11.4
11.5
6.5.4
6.5.4.3, 6.7.1
6.1.2.6, 6.5
6.8.2
6.1.2.1, 6.5.4.3
6.1.2.1, 6.5
6.7
6.7
6.1.2.1, 6.1.2.2,
6.5.4
6.1.2.2, 6.5.1,
6.5.4
6.5.7
6.5.7
6.5.2.2
6.2
6.2
6.2, 6.3.4
6.2, 6.3.4
6.3.3.3, 6.3.7
6.1.3.2
6.3.4
6.3.4
6.3.4
6.3.4
6.5.3
12.1
12.2
12.3
12.4
6.4
6.5
6.1.2
6.1.2.5
6.1.9
6.1.9
6.1.9
6.3.5
6.8.6
6.5.2.1
5.2.2
5.2.1.1
6.1.2
6.1.2.1
6.5.6
6.5.2.3
6.1.2.2
6.1.2.3
6.1.2
6.1.2.5
6.2.1.1
6.1.2.5, 6.5.2,
6.5.6
6.5.2.1
6.5.2.1
14.5
14.6
14.7
14.8
14.9
6.6.6.2
6.6.6.3
6.6.6.4
6.6.5
6.6.4.1
17.2
17.3
17.4
17.5
17.6
6.3.6, 6.3.16.2
6.3.8
6.3.2.1, 6.3.6
6.3.3.2, 6.5.4.1
6.1.2.4, 6.3.3.2
6.3
5.1.2.3, 6.3, 6.6
5.1.2.3, 6.3.3.4
5.1.2.3, 6.3.13,
6.3.14
6.3.1, 6.3.13,
6.3.14
6.3.3.3, 6.3.13,
6.3.14
6.3.3.3, 6.3.7,
6.3.10, 6.3.11
6.3.12
6.3.7
6.3.3.3
6.3.17
6.4, 6.8.1
5.2.4.2.2, 6.1.2.5
6.3.2.4, 6.3.3.1
6.3.16
6.6.4.1, 6.6.5
5.2.4.2.2, 6.3.9
6.6.5.3
6.6.5.3
6.6.5.3
5.1.2.3, 6.6.3
6.6.3
6.6.6.1
6.8.3.2, 6.8.3.3
6.8.3.2, 6.8.3.3
6.8.1
6.8
6.8
8.11
107
12.5
12.6
12.7
12.8
12.9
12.10
12.11
12.12
12.13
13.1
13.2
13.3
13.4
13.5
13.6
14.2
14.3
14.4
19.12
19.13
19.14
19.15
19.16
Appendix D (continued)
Rule
ISO ref
Rule
ISO ref
Rule
ISO ref
14.10
15.1
15.2
15.3
15.4
15.5
16.1
16.2
16.3
16.4
16.5
16.6
16.7
16.8
16.9
17.1
6.6.4.1
6.6.4.2
6.6.4.2, 6.6.6.3
6.6.4.2
6.6.4.2
6.6.4.2
6.7.1, 7.8
6.3.2.2
6.5.4.3
6.5.4.3
6.5.4.3, 6.7.1
6.3.2.2
6.5.4.1, 6.5.4.3
6.6.6.4
6.3.2.2, 6.3.3.2
6.3.6, 6.3.16.2
18.1
6.1.2.5, 6.5,
6.5.2.1
6.3.16.1
6.1.2.5, 6.3.2.3,
6.5.2.1
6.8.2
6.1.7
6.8.2
6.8.3
6.8.3, 6.8.3.5
6.8.3.5
6.8.3
6.8.3
6.8.3
6.8.3
6.8
20.1
20.2
20.3
18.2
18.4
19.1
19.2
19.3
19.4
19.5
19.6
19.7
19.8
19.9
19.10
19.11
108
20.4
20.5
20.6
20.7
20.8
20.9
20.10
20.11
20.12
21.1
21.2
Appendix D (continued)
D2. ISO 9899 references to MISRA-C:2004 rule numbers
Rule
5.1.2.3
ISO ref
Rule
ISO ref
Rule
ISO ref
6.3.6
6.3.7
6.3.8
6.3.9
6.3.10
6.3.11
6.3.12
6.3.13
6.3.14
6.3.16
6.3.16.1
6.3.16.2
6.3.17
6.4
6.5
6.5.1
6.5.2
6.5.2.1
6.6.5.3
6.6.6.1
6.6.6.2
6.6.6.3
6.6.6.4
6.7
6.7.1
6.5.2.2
6.5.2.3
6.5.3
6.5.4
6.5.4.1
6.5.4.3
6.5.6
6.5.7
6.6
6.6.3
6.6.4.1
6.6.4.2
6.6.5
109
6.8
6.8.1
6.8.2
6.8.3
6.8.3.2
6.8.3.3
6.8.3.5
6.8.6
6.8.8
7.1.3
7.1.6
7.1.7
7.3
7.5.1
7.5.6.4
7.6
7.7
7.8
7.9
7.10.1
7.10.3
7.10.6
7.12
7.13
Appendix E
Appendix E: Glossary
Underlying type
See section 6.10.4 Underlying type.
Rule scope
The MISRA rules apply to all source files in a project. That is:
Compiler library header files but not the library files only supplied as object code
It is recognised that there may be some problems getting third party source to comply but many tool and
library vendors are adopting MISRA-C for their source code.
Boolean expressions
Strictly speaking, there is no Boolean type in C, but there is a conceptual difference between expressions
which return a numeric value and expressions which return a Boolean value. An expression is
considered to represent a Boolean value either because it appears in a position where a Boolean value is
expected or because it uses an operator that gives rise to a Boolean value.
Boolean values are expected in the following contexts:
Each of these contexts requires an effectively Boolean expression which is either Boolean-byconstruct or Boolean-by-enforcement as defined below.
Boolean-by-construct values are produced by the following operators:
110
Appendix E (continued)
Boolean-by-enforcement values can be introduced by implementing a specific type enforcement
mechanism using a tool. A Boolean type could be associated with a specific typedef, and would then be
used for any objects that are Boolean. This could bring many benefits, especially if the checking tool can
support it, and in particular it could help avoid confusion between logical operations and integer
operations.
111