77范文网 - 专业文章范例文档资料分享平台

《再再论指针》修订版(3)

来源:网络收集 时间:2018-12-17 下载这篇文档 手机版
说明:文章内容仅供预览,部分内容可能不全,需要完整文档或者需要复制内容,请下载word后使用。下载word有问题请添加微信号:或QQ: 处理(尽可能给您提供完整文档),感谢您的支持与谅解。点击这里给我发消息

static char Buffer[sizeof( unsigned long ) * 2 + 1]; int i;

for( i = sizeof( unsigned long ) * 2 - 1; i >= 0; --i ) {

Buffer[i] = \Value /= 16;

}

return Buffer;

}

当然,笔者在这里介绍这些古怪的表达式仅仅为了对下标运算符进行一些探讨,并非鼓 励人们编写这样的代码。但在某些情况下,形如\这样的表达 式仍然是一个很好的选择,与下面的代码相比: Remainder = Value % 16;

if( Remainder >= 10 ) Buffer[i] = 'A' + Remainder - 10; else Buffer[i] = '0' + Remainder;

前者显然更加简明、精练,更容易阅读,所以,应根据不同的情况进行取舍。代码中使 用了除法和求余运算,有些人很喜欢把这些运算直接用移位代替,以追求极速。但现代编译 器对代码的优化已经非常出色,乘除运算与直接移位之间的效率差别已经小到几乎可以忽略 不计的程度,除非在需要进行大量数学运算或对效率极其敏感的场合,否则所提高的那么一 点微末的速度是无法弥补可读性的损失的。在可读性、空间及效率之间应进行均衡的选择, 而不是盲目追求极端。

第五章 字符串字面量---一个特殊的数组

字符串字面量(string literal)是一段双引号括起来的多字节字符序列,C/C++将其实现 为具有静态存储连续性的字符数组。初学者(包括不少书籍)常将其称为字符串常量,但这 说法只在 C++成立,C 中不成立。C 中的常量只包括下列四种: 6.4.4 Constants Syntax constant:

integer-constant floating-constant

enumeration-constant character-constant

分别是整数常量、浮点常量、枚举常量和字符常量,并不包括字符串字面量。但由于字 符串字面量具有静态存储连续性数组类型,并且在表达式中它会根据数组到指针的隐式转换 规则转换为一个代表数组首地址的右值指针,因此 C 中的字符串字面量的首地址及各元素的 地址都是地址常量表达式,但字符串字面量本身不是常量,也不是常量表达式。

而 C++的情形有所不同,C++将字符串字面量归入了常量当中: 2.13 Literals

There are several kinds of literals.21) literal:

integer-literal character-literal floating-literal string-literal boolean-literal

21) The term “literal” generally designates, in this International Standard, those tokens that are called “constants” in ISO C.

因此 C++中的字符串字面量才可称为字符串常量,而且首地址及各元素地址跟 C 一样, 都是地址常量表达式。

字符串字面量在 C 中具有数组类型 char[N],在 C++中则为 const char[N],在表达式中当 发生数组到指针的转换时,对应的等效指针类型分别是 char*和 const char*,因此,在 C 中, char *p = “ABCDEF”是合法的,但让人惊奇的是,上述语句在 C++中也是合法的!看起来 一个 pointer to const char 指针被赋予了 pointer to char 指针,似乎违反了 C++中指针转换的 more cv-qualified 原则。其实字符串字面量在 C++中存在两种转换,一种转换依据当前上下 文环境,另一种遵循数组到指针的转换,C++标准的内容: 2.13.4 String literals

??..An ordinary string literal has type “array of n const char” and static storage duration (3.7),

where n is the size of the string as defined below, and is initialized with the given characters. 4.2 Array-to-pointer conversion

A string literal (2.13.4) that is not a wide string literal can be converted to an rvalue of type “pointer to char”; a wide string literal can be converted to an rvalue of type “pointer to wchar_t”. In either case, the result is a pointer to the first element of the array. This conversion is considered only when there is an explicit appropriate pointer target type, and not when there is a general need to convert from an lvalue to an rvalue. [Note: this conversion is deprecated. See

Annex D. ] For the purpose of ranking in overload resolution (13.3.3.1.1), this conversion is considered an array-to-pointer conversion followed by a qualification conversion (4.4). [Example: \“pointer to const char” as an array-to-pointer conversion, and then to “pointer to char” as a qualification conversion. +

在具有显而易见的合适指针目标类型的情况下,例如上述 char *p = “ABCDEF”,字符 串字面量被转换为 char*而不是 const char*类型的指针,这个转换实际上是对旧有代码的兼 容,是一个特例,而且被指定为 deprecated 的,将在未来的版本中予以废弃,有些编译器 会产生一条提示这是废弃转换的警告。而在函数重载解析中,字符串字面量遵循数组到指针 的转换,同时后跟一个限定修饰的转换。

虽然字符串字面量在 C 中类型为 char[N],在 C++中类型为 const char[N],但并不说明 C 中的字符串字面量可以修改,C++的不可以。字符串字面量是否可以修改与实现数组的类型 无关,C 之所以没有规定为 const char[N],还是出于对旧代码的兼容,而 C++规定为 const char[N]的原因之一是比 C 更严格的类型安全。无论 C 与 C++都规定对字符串字面量的修改是 未定义的,编译器可以自行处理,也的确存在一些允许修改字符串字面量的编译器,例如老 一代的编译器 TC,编译器不管是否允许修改字符串字面量,都没有违反标准。

对于那些允许修改字符串字面量的编译器,必须考虑这样一个问题,当代码在不同的上 下文中引用了同一个字符串字面量时,如果其中一处修改了该字面量,就会影响其它地方的 引用。解决方法是允许同一个字面量的多个实例,这样不同上下文之间不会互相干扰,标准 把这个问题的决定权留给了编译器: 6.4.5 String literals

It is unspecified whether these arrays are distinct provided their elements have the appropriate values.

在 C 中,由于字符串字面量不是常量,而且 const 限定的变量不是常量表达式(C 中的 常量表达式必须是编译期的),因此所有的常量和常量表达式都是右值。但 C++将字符串字 面量归入常量,将 const 限定的变量归入常量表达式,这意味着在 C++中存在左值常量和左 值常量表达式。

C 与 C++在这方面的差异反映出两者对待常量的不同视角。C 认为常量是不应该拥有存 储空间的,这是非常传统的观点;而 C++把常量的概念延伸到了对象模型,是对对象概念的 有益扩展,但同时也带来了一些问题,一个具有对象性质的实体,难以避免存在某些合法或 不合法的手段去修改其内容,这种行为常常令常量对象的常量性质处于尴尬的境地,由此也 催生了常量折叠这一类巧妙的折中。

第六章 指针与 const

const 一词在字面上来源于常量 constant,const 对象在 C/C++中是有不同解析的,如第 二章所述,在 C 中常量表达式必须是编译期,运行期的不是常量表达式,因此 C 中的 const 不是常量表达式;但在 C++中,由于去掉了编译期的限定,因此是常量表达式。

对于一个指向 const 对象的指针 pointer to const T,由于把 const 视作常量表达式,常常 存在如下两种观点:

1。这是一个指向常量的指针,简称常量指针; 2。这个指针指向的内容不可改变。 这是比较粗糙的理解。虽然这个指针的类型是 pointer to const T,但不代表它指向的对 象真的是一个常量或者不可改变,例如: int i = 10;

const int *p = &i; i = 20;

p 指向的对象 i 明显不是常量,虽然 p 指向 i,但 i 的值依然可以改变。对于这个现象, C++标准有明确的论述: 7.1.5.1 The cv-qualifiers

a pointer or reference to a cv-qualified type need not actually point or refer to a cv-qualified object, but it is treated as if it does;

其中 cv 指的是 const 和 volatile,const 和 volatile 叫 type qualifier,类型限定词。const T 只是 类型假定,并非指出该对象是什么,这个对象也许是 const 限定的,也许不是。既然上述两 种看法都是不恰当的,pointer to const T 又应如何看待呢?一种比较好的理解是,将其视作 一条访问路径。对一个对象进行取值或者修改操作,可以有很多种方法,每种方法都相当于 一条能够对对象进行访问的路径,例如: int i = 10, k;

const int *p = &i; int *q = &i; i = 20; *q = 30; k = *p;

通过*q、*p 和标识符 i 都能访问 i 所代表的整数对象,它们可以视作三条路径,i 和*q 能够修改该整数对象的值,这两条路径是可写可读的;但*p 不能写,因为 p 指向的对象被 假定为 const,从 p 的角度看来,*p 是只读的,不能通过 p 修改它指向的对象。因此,一个 pointer to const T 指针的确切意义,不是指向常量或者指向的对象不可改变,而是指不能通 过这个指针去修改其指向的对象,无论这个对象是否 const,它只指出一条到该对象的只读 路径,但存在其它路径可以修改该对象。这种理解,在标准中是有根据的: 7.1.5.1 The cv-qualifiers

a const-qualified access path cannot be used to modify an object even if the object referenced is a non-const object and can be modified through some other access path.

上述条款对访问路径进行了一个清晰的描述。 一个 pointer to T 类型的指针,可以赋值给一个 pointer to const T 类型的指针,这是众所 周知的语法规则。笔者曾经一度认为,两者之所以可以赋值,是基于指针的相容性原理,以 为两者是相容的,后来翻阅了 C/C++的标准,才认识到这种解释其实是错误的,从相容性原 理来说,两者恰恰是不相容的。C 标准关于指针的相容性是这样规定的:

6.7.5.1 Pointer declarators

For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.

两个相容的指针,既要有同一的限定修饰词,所指向的类型也要相容的。而两个相容的 类型要符合如下规定:

6.2.7 Compatible type and composite type

Two types have compatible type if their types are the same.

两个相同的类型才具有相容性,那么 cont T 和 T 是否两种相同的类型呢?再看如下条款: 6.2.5 Types

The qualified or unqualified versions of a type are distinct types that belong to the same type category and have the same representation and alignment requirements.

一个类型的限定和非限定版本是同一种类类型的具有同一表示范围及对齐需求的不同 类型。这就是说,const T 和 T 不是相同的类型,两者不相容,于是,虽然 pointer to const T 与 pointer to T 具有同一的限定修饰(都没有限定词),但所指向的对象类型不是相容的类型, 因此 pointer to const T 与 pointer to T 是不相容的指针类型。

既然两者不相容,又是什么原因导致它们可以赋值呢?再查阅 C 标准关于赋值运算符的 规定,发现有这么个条款: 6.5.16.1 Simple assignment Constraints

One of the following shall hold: ???

— both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;

噢,其实原因在这里!左操作数所指向的类型要包含右操作数所指向类型的所有限定词。 pointer to const T 比 pointer to T 多一个 const,因此可以将 pointer to T 赋值给 pointer to const T,但反过来不行。通俗一点说,就是左操作数要比右操作数更严格。C++中的规定与 C 有 点不同,C++标准去掉了这一条款,代之以 more cv-qualified 的概念,一个 pointer to cv1 T 的指针,要转换为一个 pointer to cv2 T 的指针,条件是 cv2 比 cv1 要更 cv 限定化。

要注意的一点是,这条赋值运算符的规则只适用于 pointer to qualified or unqualified type,不能延伸到 pointer to pointer to qualified or unqualified type 及更高级别的指针类型, 例如: int i = 10;

const int *p = &i; /* A */ int *q = &i;

const int **p1 = &q; /* B */

A 合法,但 B 不合法。虽然 p1 与&q 都是 unqualified 的,但 p1 指向的对象类型为 pointer to const int,&q 指向的类型为 pointer to int,如前所述,两者是不相容类型,不符合两操作 数必须指向相容类型的规定,因此赋值非法。

根据上述规则,一个 pointer to const T 不能赋予 pointer to T,但是,一个 const pointer 却能赋予 non-const pointer,例如: int i;

int * const p = &i; int *q;

百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库《再再论指针》修订版(3)在线全文阅读。

《再再论指针》修订版(3).doc 将本文的Word文档下载到电脑,方便复制、编辑、收藏和打印 下载失败或者文档不完整,请联系客服人员解决!
本文链接:https://www.77cn.com.cn/wenku/zonghe/373683.html(转载请注明文章来源)
Copyright © 2008-2022 免费范文网 版权所有
声明 :本网站尊重并保护知识产权,根据《信息网络传播权保护条例》,如果我们转载的作品侵犯了您的权利,请在一个月内通知我们,我们会及时删除。
客服QQ: 邮箱:tiandhx2@hotmail.com
苏ICP备16052595号-18
× 注册会员免费下载(下载后可以自由复制和排版)
注册会员下载
全站内容免费自由复制
注册会员下载
全站内容免费自由复制
注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: