共1条
1/1 1 跳转至页
The Embedded C++ Programming Guide Lines(老站转)
不错的一篇文章, 希望有人能将其翻译为中文.
The Embedded C++ Programming Guide Lines
Version WP-GU-003,Copyright(C) 6,Jan 1998 by the Embedded C++ Technical Committee
--------------------------------------------------------------------------------
Embedded C++ Programming Guide
A. Migrating from C language to C++ language
A.1 Character constant
Note
In C, a character constant has type int. In C++, it has
type char.
Example
i = sizeof('a');
In C, this stores sizeof(int) (which is likely to be
greater than 1) into i. In C++, it stores sizeof(char)
(which is always 1) into i.
Guideline
When migrating code from C to C++, rewrite expressions
that depend on the size of a character constant to remove
the dependency.
A.2 Object declaration at file scope
Note
In C++, a declaration of an object at file scope without a
storage class specifier is a definition of that object
with external linkage. If the definition does not have an
initializer, the object has initial value 0. (As in C, an
object declared in a C++ program must be defined exactly
once.)
In C, a declaration of an object at file scope without a
storage class specifier and without an initializer is a
tentative definition, which may appear more than once in a
translation unit.
Example
int a; /* (1) */
int a = 10; /* (2) */
In C, (1) is a tentative definition. Since (2) is
unequivocally a definition, C treats (1) as a mere
declaration.
In C++, both (1) and (2) are definitions. In the
presence of (1), (2) is a duplicate definition, and
therefore an error.
Guideline
In C++, a declaration of an object at file scope is just a
declaration (and not also a definition) if and only if it
has an explicit extern specifier and no initializer.
Each object declared at file scope must be defined exactly
once. All but one declaration must have both an explicit
extern specifier and no initializer.
A.3 const type qualifier
Note
In C, a const-qualified object at file scope without an
explicit storage class specifier has external linkage. In
C++, it has internal linkage.
Example
+- file1 --------------------+
| extern const int n; |
+----------------------------+
+- file2 --------------------+
| const int n = 10; |
+----------------------------+
In C, object n of file2 has external linkage, so it can
satisfy the reference to n (also with external linkage) in
file1. In C++, object n in file2 has internal linkage,
and will not satisfy the reference to n in file1.
Guideline
Const-qualified objects with external linkage must have an
explicit extern specifier.
A.4 Conversion to void *
Note
In C, there is a standard conversion from void * to T *
(for any object type T). In C++, there is no such
conversion. Such conversions require a cast in C++.
The following Standard C library functions return void *:
calloc, malloc, realloc, bsearch, memcpy, memmove,
memchr, memset
C++ requires an explicit cast when assigning the return
value of such a function to a pointer to non-void type.
Example
int* p;
p = malloc(10 * sizeof(int));
In C++, the assignment to p requires an explicit cast, as
in
p = (int *)malloc(10 * sizeof(int));
Guideline
In C++, use operator new instead of calloc, malloc, or
realloc. (See item A.12).
Ignore the return value of a memcpy, memmove, and memset.
(They just return their first argument converted to void
*.)
For all other functions that return void * (standard or
user-defined), use an explicit cast when converting the
return value to another pointer type.
A.5 Enumeration type
Note
In C, enumerations are integral types. A program can
convert from an enumeration type to an integral type, and
back, without a cast. A C program can apply ++ and -- to
an enumeration object.
In C++, each enumeration is a distinct type. There are
standard conversions from enumeration type to integral
types, but not from integral types to enumeration types.
A C++ program cannot apply built-in ++ and --, nor any
compound assignment (such as +=) to an enumeration object.
Example
enum RGB { red, green, blue } rgb;
++rgb;
++rgb is an error in C++ if it uses the built-in ++
operator. It means the same as
rgb = rgb + 1;
This is also an error unless you write it with a cast:
rgb = RGB(rgb + 1);
The best alternative is to implement an operator++ for
type RGB, as in
RBG &operator++(RGB &x)
{
return x = RGB(x + 1);
}
Guideline
When converting a C program to C++, provide typesafe
implementations for operator++ and operator-- as needed
for enumeration types.
A.6 Type definition in cast, parameter declaration, or sizeof
Note
In C, types can be defined in a cast expression, parameter
declaration or sizeof expression. In C++ they cannot.
Example
void func(struct TAG { int a; } st)
{
...
}
Here, TAG is defined in the parameter declaration.
Guideline
Define a type used in a parameter declaration in the scope
enclosing the function declaration, or some larger
enclosing scope.
Define a type used in a cast expression or sizeof
expression in the scope enclosing the expression, or some
larger enclosing scope.
A.7 Transfer of control past the definition of a local object
Note
In C, a goto or switch statement may transfer control
beyond the definition of an object at block scope,
possibly bypassing initialization. In C++, it may not.
Example
goto LABEL;
{
int v = 0;
...
LABEL:
...
}
This is valid in C, assuming the code following LABEL:
does not depend on v being initialized to 0. It is always
an error in C++.
Guideline
Do not use goto or switch statements to bypass
initialization of a local object.
A.8 Character array initialization
Note
A C program can initialize an array of characters using a
string literal that defines one more character (counting
the terminating '\0') than the array can hold.
A C++ program cannot.
Example
char s[3] = "abc";
The size of the array is three, though the size of the
string literal is 4. This is valid in C, but not C++.
Guideline
Do not initialize an array of characters using a string
literal with more characters (including the '\0') than the
array. Therefore, it is necessary to specify the correct size of
a string literal (char s[4] = "abc";).
However, because the result of the expectation always can be
obtained even if the size of the string literal is changed,
the method of not describing the size (char s[] = "abc";) is
recommended.
A.9 Prototype declaration
Note
A C++ program requires that you declare a function
prototype before calling the function. In C, a call to
an undeclared function is permissible. Moreover, a C++
program interprets the function declarator 'f()' as
equivalent to 'f(void)' -- a function with no arguments.
In C, the same declaration leaves the number and types
of the parameters unspecified.
Example
extern void func();
....
sub();
func(0);
The call to function 'sub' is an error because there is no
prototype declaration. The call to function 'func' is
also an error because its declaration says it has no
arguments.
Guideline
Always declare the prototype before calling a function.
To emphasize that function 'f' is called with no
arguments, write its declarator as 'f(void)'.
A.10 Keywords added in C++
Note
The following C++ keywords are not keywords in C:
asm bool catch class
const_cast delete dynamic_cast explicit
false friend inline mutable
namespace new operator private
protected public reinterpret_cast
static_cast template this throw
true try typeid typename
using virtual wchar_t
Example
int class, new, old;
This declaration is valid in C, but not in C++.
Guideline
Do not use a C++ keyword as an identifier.
A.11 Scope of nested types
Note
In C, the name of a type defined inside a struct or union
is actually in same scope as the name of the enclosing
struct or union. In C++, the name of the nested type is
within the scope of the enclosing struct or union.
Example
struct S {
int a;
struct T {
int t;
} b;
int c;
enum E { V1, V2 } e;
};
struct T x;
enum E y;
The declarations for x and y are valid in C, but not in
C++. In C++, the names T and E are not in scope outside
the definition of struct S.
Guideline
Do not define the name of a type as nested unless all uses
of that name are also in the scope of the enclosing
struct/union.
A.12 Dynamic memory management
Note
There is no guarantee that new and delete apply the same
memory management policy to the same memory as do malloc
and free. Therefore, a program cannot delete memory
unless that memory was previously acquired by new, and it
cannot free memory unless that memory was acquired by
malloc (or calloc or realloc).
Example
int (*p)[10];
p = (int (*)[10])malloc(sizeof(*p));
....
delete p;
The delete expression has undefined behavior.
Guideline
In C++, avoid malloc, calloc, realloc and free; use only
new and delete.
A.13 '/*' after '/'
Note
Writing the C-style comment '/* */' immediately after
the token '/' is interpreted as the C++-style comment
'//' instead.
Example
i = j //* comment */ k ;
The sequence '//' is interpreted as a comment delimiter.
The expression is interpreted not as 'i = j / k;' but as
'i = j'.
Guideline
Avoiding writing a C-style comment '/**/' immediately
after the token '/'.
B. Guidelines for Code Size
B.1 Object initialization
Note
There are various ways to specify the initialization of an
object. Some initializations generate unnecessary
temporary objects, and result in larger code size.
For example:
T x(i) // (1)
T x = i; // (2)
T x = T(i) // (3)
T x; // (4)
x = i; //
(1) This applies a constructor directly to object x
without using a temporary object, as if by calling:
x.T(i); // apply constructor to x
(2) In some implementations, this applies a constructor
directly to x as above. In others, it constructs a
temporary object, and initializes x from the
temporary, as if by calling:
temp.T(i); // apply constructor to temp
x.T(temp); // apply copy constructor to x
temp.~T(); // apply destructor to temp
(3) This is the same as (2).
(4) This initializes x using T's default constructor, then
later assigns a new value to x using an assignment
operator. The assignment operator may release
resources that x is using and acquire new resources.
x.T(); // apply default constructor to x
x.operator=(i); // apply assignment operator to x
Guideline
Use declarations of form (1) above in preference to the
other forms.
B.2 Inline specifier
Note
Inline expansion reduces the overhead of function entry
and exit, but it may increase code size.
Member functions in class definitions are expanded inline
by default.
Guideline
Use inline specifier for only small functions. A member
function for which inline expansion is not appropriate
should be defined outside the class definition, so that it
is not inline expanded.
B.3 Temporary objects for return values
Note
Calling a Function that returns an object by value may
create and destroy a temporary object, thus increasing by
code size and execution time.
Example
class Matrix {
int a, b;
public:
Matrix &operator+=(const Matrix &);
friend
Matrix operator+(const Matrix &, const Matrix &);
};
Matrix operator +(const Matrix &, const Matrix &)
{
...
}
void func()
{
Matrix a,b;
a = a + b; // (1)
a += b; // (2)
}
(1) calls operator+, which returns a Matrix by value. In
some implementations this creates (and later destroys) a
temporary Matrix object.
(2) calls operator+=, which generates no temporary Matrix
objects.
Guideline
For objects of class types, use compound assignment
operators (such as += in preference to + and =) to avoid
creating and destroying temporary objects unnecessarily.
B.4 Operators new and delete
Guideline
Implement class-specific operators new and delete as
needed to improve the speed and memory utilization of
dynamic memory management.
B.5 Initialization of global objects
Note
The order of initialization of global objects is
implementation-dependent. However, the order of
initialization in a single translation unit is guaranteed
to be the order of declaration.
Example
file1 file2 file3
int a = f(); int b = f(); int f(void)
{
static int a = 0;
return a++;
}
The program may initialize 'a' with 0 and 'b' with 1, or
vice versa, depending on the order the implementation
chooses to initialize them.
It is possible to make the initialization order well
defined by moving the declaration of 'b' in file2 to
file1, as in:
file1 file2 file3
int a = f(); int f(void)
int b = f(); {
static int a = 0;
return a++;
}
The order of initialization is a, then b.
Guideline
Avoid coding which depends on the initialization order of
global objects across translation units.
C. Guidelines for speed
C.1 new and delete for array of class objects
Note
Declaration of an array of class objects calls its
element's constructor for each element. The program calls
the destructor for each element when the array goes out of
scope. The processing time of the constructor/destructor
may be unexpectedly long. This can be a problem for
real-time processing.
Guideline
Avoid creating and destroying a large array of class
objects during time-critical processing.
C.2 Object declaration in loops
Note
When a class variable is declared in a loop, its
constructor and destructor are called in each iteration.
The overhead of construction and destruction may slow the
loop.
Example
for (i = 0; i < 1000; i++)
{
FOO a;
...
}
Guideline
Avoid declaring a class variable inside a loop. Declare
it outside the loop instead.
D. Guidelines for ROMable code
D.1 const objects in ROM
Note
In general, a const-qualified object can reside in ROM if
it:
-- has static storage duration,
-- is initialized by a constant expression, and
-- has a POD (plain old data) type.
A POD type is any of:
-- a scalar (arithmetic, enumeration or pointer) type
-- a class, struct, or union all of whose data members
are public and of POD types, and with no user-defined
constructor or destructor, no base classes, and no
virtual functions
-- an array with elements of POD type
Example
static const char lang[] = "EC++";
class A {
int a;
public:
A();
~A();
};
const A x;
'lang' may be placed in ROM; 'x' may not.
Guideline
Declare objects to be placed in ROM with POD types and
with constant initializers.
NOTE: The form of presentation used here, and several of the specific
guidelines, were inspired by the excellent book by Thomas Plum and
Dan Saks, 'C++ Programming Guidelines' (Plum Hall Inc., 1991).
关键词: Embedded Programming Guid
共1条
1/1 1 跳转至页
回复
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
【换取逻辑分析仪】-基于ADI单片机MAX78000的简易MP3音乐播放器被打赏48分 | |
我想要一部加热台+树莓派PICO驱动AHT10被打赏38分 | |
【换取逻辑分析仪】-硬件SPI驱动OLED屏幕被打赏36分 | |
换逻辑分析仪+上下拉与多路选择器被打赏29分 | |
Let'sdo第3期任务合集被打赏50分 | |
换逻辑分析仪+Verilog三态门被打赏27分 | |
换逻辑分析仪+Verilog多输出门被打赏24分 | |
【分享评测,赢取加热台】使用8051单片机驱动WS2812被打赏40分 | |
【换取逻辑分析仪】rtthread添加RRH62000传感器驱动-基于野火启明6M5被打赏48分 | |
换逻辑分析仪+Verilog多输入门被打赏27分 |