1、Macrouse is best confined to naming literal constants, and providing shorthand for afew well-chosen
constructs. Define the macro name all in capitals so that, in use, it'sinstantly clear it's not a function
call. Shun any useof the C preprocessor that modifies the underlying language so that it's nolonger C.
(宏最好只用于命名常量,并为一些适当的结构提供便捷的记法。宏名应该大写,这样便很容易与函数调用区分开来,千万不要使用C预处理器来修改C语言的基础结构,因为这样一来C语言就不再是C语言了。)
2、①test one :
foo(const char *p) { }
main(int argc, char *argv)
{
foo(argv);
}
②test two :
foo(const char **p) { }
main(int argc, char **argv)
{
foo(argv);
}
test one is OK;
test two warning: argument is incompatible withprototype
Why???
argument passingis supposed to behave like assignment.
Thus, a diagnostic message must be produced unless an object of type const char**may be
assigned a value of type char **.To find out whether this assignment is legal,flip to the section
on simple assignment, Section 6.3.16.1, which includes the followingconstraint:
One of the following shall hold:…
• Both operands are pointers to qualified or unqualified versions ofcompatible types, and the
type pointed to by the left has all the qualifiers of the type pointed to bythe right.
It is this condition that makes a call with a char *argument corresponding to aconst char *
parameter legal (as seen throughout the string routines in the C library). Thisis legal because in the
code
char * cp;
const char *ccp;
ccp = cp;
• The left operand is a pointer to "char qualified byconst".
• The right operand is a pointer to "char" unqualified.
• The type charis a compatible type with char, and the type pointed to bythe left operand
has all the qualifiers of the type pointed to bythe right operand (none), plusone of its own
(const).
Note that the assignment cannot be made the other way around. Try it if youdon't believe me.
cp = ccp; /* results in a compilation warning */
Does Section 6.3.16.1 also make a call with a char **argument corresponding toa const
char **parameter legal? It does not.
The Examples portion of Section 6.1.2.5 states:
The type designated "const float *" is not a qualified type—its typeis "pointer to const-qualified float"
and is a pointer to a qualified type.
Analogously, const char **denotes a pointer to an unqualified type. Its type isa pointer to a
pointer to a qualified type.
Since the types char **and const char **are both pointers to unqualified typesthat are
not the same type, they are not compatible types.Therefore, a call with anargument of type char
**corresponding to a parameter of type const char **is not allowed. Therefore,the
constraint given in Section 6.3.2.2 is violated, and a diagnostic message mustbe produced.
This is a subtle point to grasp. Another way of looking at it is to notethat:
• the left operand has type FOO2—a pointer to FOO, where FOO is anunqualified pointer to a
character qualified by the const qualifier, and
• the right operand has type BAZ2—a pointer to BAZ, where BAZ is anunqualified pointer to
a character with no qualifiers.
FOO and BAZ are compatible types, but FOO2 and BAZ2 differ other than inqualifica-tion of the
thing immediatelypointed to and are therefore not compatible types; thereforethe left and right
operands are unqualified pointers to types that are not compatible.Compatibility of pointer types is
not transitive. Therefore, the assignment or function call is notpermitted.However, note that the
restriction serves mainly to annoy and confuse users. The assignment iscurrently allowed in C++
translators based on cfront (though that might change).
3、Advice on Unsigned Types
Avoid unnecessary complexity by minimizing your use of unsigned types.Specifically,
don't use an unsigned type to represent a quantity just because it will neverbe negative
(e.g., "age" or "national_debt").
Use a signed type like intand you won't have to worry about boundary cases inthe
detailed rules for promoting mixed types.
Only use unsigned types for bitfields or binary masks. Use casts inexpressions, to make all
the operands signed or unsigned, so the compiler does not have to choose theresult type.
4、Need Some Temporary Store? Be the First onYour Block!
需要一些临时变量吗?把它放在块的开始处!
5、Our preference is not to mix a structdeclaration with definitions of variables. We prefer
struct veg { int weight, price_per_lb; };
struct veg onion, radish, turnip;
to
struct veg { int weight, price_per_lb; } onion, radish, turnip;
Sure, the second version saves you typing a few characters of code, but weshould be much more
concerned with how easy the code is to read, not towrite. We write code once,but it is read many
times during subsequent program maintenance. It's just a little simpler to reada line that only does one
thing. For this reason, variable declarations should be separate from the typedeclaration.