Chapter 4. Types and Declarations

 
这一章的内容结构和阅读要点(红:认真读 绿:大致读 蓝:回头读)
 
l类型的基本概念(4.1);
l布尔类型(4.2);
l字符类型(4.3);
l整数类型(4.4);
l浮点数类型(4.5);
l获得特定类型的数据所占有的存储空间量(4.6);
lvoid类型( 4.7 )
l枚举类型(4.8);
l用类型来定义变量(实例化)(4.9)。 
 
4.1 Types
 
l类型是C++语言的核心概念之一。掌握一种语言的根本在于准确、深刻地理解语言的类型(Type/Class)。这一章通过介绍几种典型的类型,来建立类型和声明这两个基本概念。
l在用C++语言写的任何一个程序中,所出现的每一个  
      标识符(Identifier),如变量(Variables)、常量(Constants)、函数(Functions)等,
      字面值(Literals),
      运算符/操作符(Operators),
      以及以上元素的合法组合,如表达式(Expressions)等,  
都有特定的类型。
 
l在一个程序中,每个类型都有着相互不同的名称。 
 
l类型的作用:  
w决定变量或常量的合法取值范围(值集,A Set of Values)。
w决定合法的(一般是用运算符或函数表示的)操作的范围(操作集,A Set of Operations)。
w决定变量的存储空间的大小。
w区分名字相同、类型不同的符号(变量、函数、运算符)。
w决定将一种类型的值能否及如何转换成另一种类型的值。
w为编译程序提供依据,令其检查出程序中的一部分错误。 
 
lC++ has a set of fundamental types(基本类型)corresponding to the most common basic storage units of a computer and the most common ways of using them to hold data:
 
wBoolean(布尔)type
wCharacter(字符)types
wInteger(整数)types
wFloating-point(浮点数)types
wVoid type  
lA user can define:  
wEnumeration(枚举)types  
lFrom these types, we can construct other types:  
wPointer(指针)type
wArray(数组)types
wReference(引用)types
wData structure(结构)and classes(类)

4.2 Booleans 
l布尔类型的名称:bool。
l布尔类型的值集:{ true, false }。
l布尔类型的值可以承受算术运算和逻辑运算,这时,布尔类型的字面值true和false分别被转换成(机器中)整数类型的值 1 和 0,程序中的非零值代表true,0为false。
l布尔类型的主要用途:  
w定义那些表达逻辑运算
 (logical operations)结果的变量;
w作为函数(用于测试某些条件—a predicate)的返回类型。 

      Conversely, integers can be implicitly converted to bool values: nonzero integers convert to true and 0 converts to false. 

      A pointer can be implicitly converted to a bool. A nonzero pointer converts to true; zero-valued pointers convert to false.
4.3 Character Types
 
l字符类型的名称:char(unsigned char);signed char;wchar_t。
lchar类型和signed char类型的值集:ASCII字符集(ISO-646)256个。
lwchar_t类型的值集:Unicode字符集(ISO-10646)。
lchar类型值的存储空间(一般是1个字节(1 byte,8 bits))。
l字符类型的值可以承受算术运算和逻辑运算。这时,字符类型的每个值被转换成对应的一个整数(char类型为0~255,signed char类型为
     -128~127)。
l字符字面值的类型为char,是用单引号括起来的单个字符,或者是用单引号括起来的、前加转义符 \ 的单个字符,如\t, \n等,或为‘\ddd’及‘\xhh’。 
 
例:
char  c;
unsigned char tab = ’\t’;
bool  b;
c = ’A’;
b = c = = ’A’;      // true
b = c = = tab;     // false
b = (c + 1) = = ’B’; // true
b = c > ’a’; // false
 
4.4 Integer Types
 
l整数类型的名称:int(signed int);unsigned int; short(signed short);unsigned short;long(signed long);unsigned long。
l整数类型的值集:整数集合的子集。
l整数类型值的存储空间与平台(Platform,通常指特定的机器和操作系统)相关,典型的存储空间分配量是,short:2 字节;int:4 字节;long:8 字节。
l整数类型的值可以承受算术运算和逻辑运算。
l整数字面值是由+/-号、数字组成的串,它共分三类:即十进制(0~9)、八进制(0~7)、十六进制(0~9, a~f/A~F)。前加0为八进制,前加0x为十六进制;后加U为无符号整数字面值,后加L(l)为长整数字面值。
l注意采用正确的整数类型和进制。(P73) 
 
lThe unsigned integer types are ideal for uses that treat storage as a bit array. Using an unsigned instead to an int to gain one more bit to represent positive integer is almost never a good idea。
lOctal and hexadecimal notations are most useful for expressing bit patterns. Using these notations to express genuine(真正的) numbers can lead to surprises。 
 
例:
int   i,j, k;
long  n = 123456789L;
unsigned short s;
i = 0x53;     // i的值为83
j = i - 010;  // j的值为83-8=75
n = n - i + j;
s = 1;        // s的值为0000000000000001(二进制)
s = s << 3;   // 左移三位后s为0000000000001000
k = s;        // k的值为8  
4.5 Floating-Point Types

 
l浮点数类型的名称:float;double;long double。
l浮点数类型的值集:实数集合的子集。
l浮点数类型的变量/值的存储空间与平台相关。
l浮点数类型的值可以承受算术运算和逻辑运算。
l浮点运算必须注意的三个问题:
      ◆  精度与误差; 
      ◆  判相等问题; 
      ◆  整数与实数之间进行转换时的问题。
l浮点数字面值是由+/-、小数点、数字和 e(表示指数)组成的串,后加 f 或 F 为float类型,后加 l 或 L 为long double类型,后面什么也不加为double类型(default)。 
 
例:
long  n = 123456789L;
float f;
double d;
long double d2;
f = 1234567.89f;
d2 = f / 1.23e5L;  // 1234567.89/123000.0
d = n + 1000000L;  // d的小数部分未必为0
f = f + 0.0000001; // 精度的限制可能使f的值不变 
 
4.6 Sizes
 
l类型的作用之一是决定应当为变量分配的存储空间,而存储空间对于某些类型(如整数类型、浮点数类型等)又决定了它的值集。
l对同一C++类型的存储空间分配规则,在不同平台中可能不同。
l我们在写程序时,要注重程序的可移植性(Portability),避免与特定平台的存储空间分配规则密切相关。
l一种有效的做法是:用操作符sizeof来获得特定类型的存储空间分配量,而不是用整数类型字面值直接表示。  
例:
/* 定义一个10k的通信缓冲区。在这个缓冲区中,前半部
   分用来存储10个int值,使用前需要进行初始化,预先
   置为全空格。
*/
char  buffer[10 * 1024];
/* 用sizeof来确定这一部分的长度将与平台无关 */
memset(buffer, 32, sizeof(int) * 10);
/* 如果用整数类型字面值来指明长度,可能会发生可移
   植性问题:*/
memset(buffer, 32, 20);  // 对于Unix是长度不足的 
 
l不论在具体平台上的实际分配量是多少,C++都把分配给一个char类型值的存储空间量,作为存储空间分配的基本单位量,其他类型值的存储空间分配量都是这个基本单位量的整数倍。
l虽然具体的存储空间分配量与平台相关,但始终保持以下关系: 
                                                                 Chapter 4. Types and Declarations - johnlxj - johnlxj的博客

 
 
4.7 Void
 
lVoid类型的名称:void。
lVoid类型的值集:F(空集)。
lVoid类型一般只用来表示不返回值的函数(过程,pseudo return type),以及构造出不限制所指对象类型的指针类型(void *),来指向类型不限或类型不可预知的对象。
lNotice that there is no objects of type void.  
4.8 Enumerations 
lEnumeration是用户以枚举值集的方式定义的类型。
lEnumeration值集中的每个值都是一个已命名的整数常量(Named integer constant),这个名字就是Enumeration类型的一个字面值(枚举符, enumerator)。 
 
例:
// 若不指明对应的整数值,从0开始递增
enum keyword { ASM, AUTO, BREAK };
// 也可以指明对应的整数值(注意:值不能重复)
enum summer_month { Jun = 6, Jul = 7, Aug = 8 };  
 
l一个Enumeration类型变量的取值范围为0(或-2n-1)~+2n-1。 
 
例:
enum e1{dark, light};    //range 0~1
enum e2{a=3, b=9};       //range 0~24-1
enum e3{min=-10, max=10000000 } //range –1048576~1048575  
 
例:
enum flag{ x=1, y=2, z=4, e=8 }; //range  0~15
flag f1=5;            //type error: 5 is not a type flag 
flag f2=flag(5);      //correct: flag(5) is of type flag and within the range of flag
Flag f3=flag(z|e);    //correct: flag(12) is of type flag and within the range of flag
Flag f4=flag(99);     //error : 99 is not within the range of flag
 
lEach enumeration is a distinct type. 
 
lEnumeration类型的主要用途,是以易于理解、易于控制的方式表示程序中需要区分的状态,that is give both the user and the compiler a hint as to the intended use. 
 
/* 既不容易理解、也不容易控制的
   状态表示 */
void getAJob( int p )
{
  switch (p) {
    case 0:  // 0代表程序员
      // 程序员求职处理
      break;
    case 1:  // 1代表软件工程师
      // 软件工程师求职处理
      break;
  }
}

 
enum Position
  { programmer, software_engineer };
void getAJob( Position p )
{
  switch (p) {
    case programmer:
      //程序员求职处理
      break;
    case software_engineer:
      //软件工程师求职处理
      break;
  }
}  
4.9 Declarations 
lBefore a name (identifier) can be used in a C++ program, it must be declared. That is, its type must be specified to inform the compiler to what kind of entity the name refers.
  (当一个名字(标识符)能够在一个C++程序中使用之前,必须先声明这个名字。这就是说,必须指明这个名字的类型,以通知编译程序这个名字所指的是哪一种类型的实体。) 
 
l声明分为定义声明和非定义声明两种。
l定义声明为所定义的名字进行的动作是:确定类型;分配存储空间;绑定(Binding,由编译程序将一个名字与它对应的存储空间关联在一起的动作);按照语言既定的省缺值(Default value)或者声明中给出的初始化动作(如果有的话)设置对应变量的初值(Initial Value)。这些动作统称为对应类型的一次实例(Instance)生成。定义声明也可以用来定义新的类型或者新的类型名。
l非定义声明是为那些还没有定义声明(或者在其他地方已定义声明)却需要在这里使用的名字,进行“先承认再核实”的声明。
l用户定义的所有名字都必须有对应的定义声明。 
 
// 定义声明
// 定义新的类型:
struct Date{ int d, m, y; };
enum   Beer{ Tsingtao,Hans,Baoji };
// 定义新的类型名:
typedef void* ent;
// 定义变量、常量和函数
char   ch, *chp;
int    i, count = 1;
const  double pi = 3.1415926;
int Day(Date* p) { return p->d; } 
 
// 非定义声明
// 超前引用
double sqrt( double );
struct Usr;
// 外部变量
extern int error_number;
// 外部函数
extern double getBeerPrice( Beer ); 
  4.9.1 The Structure of a Declaration

         A declaration consists of four parts: an optional "specifier," a base type, a declarator, and an optional initializer.

         A specifier is an initial keyword, such as virtual and extern, that specifies some non-type attribute of what is being declared.

         A declarator is composed of a name and optionally some declarator operators.

                                                             Chapter 4. Types and Declarations - johnlxj - johnlxj的博客 

  4.9.2 Declaring Multiple Names

     例:int x, y;   // int x; int y;

     Note that operators apply to individual names only - and not to any subsequent names in the same declaration.

     例:int* p, y;   // int *p; int y; NOT int* y;

            int x, *q;   // int x; int *q;

            int v[10], *pv;      // int v[10]; int* pv; 
  4.9.3 Names
 
l标识符(identifier)的命名规则:
     ◆ A name consists of a sequence of letters and digits. The first character must be a letter. The underscore character _ is considered a letter.
    ◆ 标准中对标识符的长度不限,但具体的机器对标识符的长度有限制。
    ◆ A C++ keyword cannot be used as a name of a user-defined entity.
    ◆ Names starting with an underscore are reserved for special facilities in the implementation and the run-time environment, so such names should not be used in application programs. 
 
◆ It is best to avoid names that differ only in subtle ways.
     ◆ Choose names to reflect the meaning of an entity rather than its implementation.
          ◆ Try to maintain a consistent naming style.
     ◆ Use all capitals for macros (宏) and use underscores to separate words in an identifier.
    ◆ Names from a large scope ought to have re and reasonably obvious relatively long and reasonably obvious name. However, code is clearer if names used only in a small scope have short, conventional names.
     ◆ Choosing good names is an art. 

  4.9.4 Scope
l为提高资源的利用率,允许在不同的、确定的区域使用相同的名字。顾名思义:一个名字的作用域(Scope)即为该名字起作用的区域。
l名字的作用域与函数和块(Blocks)的结构相关。C++用一对符号{} 来标识函数的源码边界和块 。块允许嵌套(Nesting)。
l在函数内、函数的参数表内和块内定义的名字称为局部(Local)量,在函数之外定义的名字称为全局(Global)量。
l变量的生存期(Life cycle)由它的作用域来决定。
l作用域规则:如果在一个函数或一个块中定义了在其外已经定义过的名字,则外部定义的名字在内部被屏蔽;否则,外部定义的名字“透入”内部。 
    A hidden global name can be referred to using the scope resolution operator ::. There is no way to use a hidden local name.
l作用域的例子: 
 
int  x;       // 全局量(x1)
void f(int x) // 局部量(x2)
{
  int x;      // 局部量定义冲突
  x = 1;      // x2的值为1
  {
    int x;    // 局部量(x3)
    x = 2;    // x3的值为2
    ::x = 3;  // x1的值为3
  }

 
lHiding names is unavoidable when writing large programs. However, a human reader can easily fail to notice that a name has been hidden. Because such errors are relatively rare, they can be very difficult to find. Consequently, name hiding should be minimized.

lUsing names such as i and x for global variables or for local variables in a large function is asking for trouble.

lThere is no way to use a hidden local name. 

   4.9.5 Initialization

       If no initializer is specified, a global, namespace, or local static object(collectively called static objects) is initialized to 0 of the appropriate type. Local variables(sometimes called automatic objects) and objects created on the free store (sometimes called dynamic objects or heap objects) are not initialized by default.

例: 

         int a;      // means "int a = 0;"

         double d;       // means "double d = 0.0;"

         void f()

        {

                 int x;    // x does not have a well-defined value

                 // ....

         }

        User-defined types may have default initialization defined.

       Note that an empty pair of parentheses () in a declaration always means "funtion".

 例:

    int a[] = {1, 2};           // array initialization

    Point z(1, 2);             // function-style initializer (initialization by constructor)

    int f();                       // function declaration

  4.9.6 Objects and Lvalues

       An object is a contiguos region of storage; an lvalue is an expression that refers to an object.

      Objects declared in global or namespace scope and statics declared in functions or classes are created and initialized once (only) and live until the program terminates.
  4.9.7 Typedef 
lTypedef
     A declaration prefixed by the keyword typedef declares a new name for the type rather than a  new variable of the given type. 

例: 
typedef char* Pchar;
Pchar p1,p2;  // p1 and p2 are char*
Typedef unsigned char uchar;   
要点与引伸

l程序中的类型机制好比一个“法律体系”,分门别类地规定了各种类别社会成员的范围、生存空间、生存期、所享有的权利、应当遵守的规则(包括允许变通的规则)、违法以后应当受到的惩罚,而执法者则是编译程序。
lC++的基本类型好比这个“法律体系”的“宪法/基本法”。
l这个“法律体系”的“法理”是:先声明所涉及的法条与作用对象,再由执法者依此进行检查,最后由对象进行法律允许的活动。
l这个“法律体系”允许程序员自己在已有法律的基础上继续定义新的法律(自定义类型),但执法者不变。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

johnlxj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值