(17)'c++:COMPLETE REFERENCE' 第一部分 第二章(表达式) 第九节操作符(2)

操作符(2)

位操作符

      与其它语言不同,c++提供了完整的位操作符。C语言设计的目的就是为了取代汇编语言来完成大部分的编程任务。这就要求C语言必须支持所以汇编语言可以完成的操作,包括位操作。位操作包括位测试、置位、移位等基于字节或者字中的自然位的操作。对应的数据类型往往是char和int等。不能对float、double、long double、void、bool等复杂的数据类型进行位操作。表2-6列出了所有位操作符。这些操作符是对操作数的每一位分别进行操作的。

表2-6.    位操作符

Operator                       Action
&                              AND
|                              OR
^                              Exclusive OR(XOR)
~                              One's complement(NOT)
>>                             Shift right
<<                             Shift left

      位操作符AND、OR和NOT和它们所对应的逻辑操作符有相同的真值表,不同的是它们是对每一位分别进行的。 下面是XOR异或的真值表:

p                q                  p^q
0                0                   0
1                0                   1
0                1                   1
1                1                   0

      正如真值表所展示的,XOR在两个操作数有且仅有一个为1时才返回true。

      位操作符常常在编写设备驱动的时候用到,如modem驱动,硬盘文件驱动,打印机驱动。因为位操作符可以用来划分特定的位,例如奇偶校验位。(奇偶校验位的作用时用来确定字节中的其余各位没有意外的改变。常常用最高位作为一个字节的奇偶校验位。)

      AND位操作符常常被当作位清除(置为0)工具 。一个操作数的某一位为0,则AND操作后另一个操作数的对应位一定会被置为0。例如,下面的整个函数会从modem中读取一个字节并且把它的奇偶校验位重新置为0:

char get_char_from_modem( void )
{
    char ch;

    ch = read_modem();   /* get a charactor from the modem */

    return( ch & 127 );
}

      奇偶校验位通常时第8位。通过与一个第1到7为1,第8位为0的操作数执行AND操作会将该字节的第8未置为0,而其它位则保留原来的状态。

      OR位操作符常常作为置位工具(置为1)。可以通过OR操作将对象操作数的指定位置为1。例如:

 10000000      128 in binary
 00000011      3 in binary
|________      bitwise OR
 10000011      result

      异或(Exclusive OR)常常简写成XOR,它的作用是当两个操作符对应位上的状态不同时,产生1。如:

 01111111   127 in binary
 01111000   120 in binary
^________   bitwise XOR
 00000111   result

      记住,关系和逻辑操作符表达式得出的结果一定时true或者false,然而位操作后会产生与该操作相对应的数值。换句话说,位操作会产生除了0和1之外的各种数值。

      移位操作符<<和>>会把一个数值中的所有位都左移或者右移。移位操作语句通常格式如下:

value >> number of bit positions
value << number of bit positions

      当一端的位被移除时,另一端的空位会补充0。(当遇到带符号数的负数时,右移操作执行后会在左边空出的位上补1,以确保该数值的符号不变。)记住,移位和循环(循环移位)不同,也就是说当一位从末端被移出之后不会补充到另一端,而是被丢弃。

      移位操作在对外设的输入进行解码的时候非常有用,如D/A转换(数模转换),读取状态信息等。移位操作也可以快捷的完成整数的乘或者除运算。右移移位等价于将一个数除以2,左移则等价于乘以2。表2-7中有详细的描述。下面先看一个程序的例子:

/* A bit shift example. */
#include <stdio.h>

int main( void )
{
    unsigned int i;
    int j;

    i = 1;

    /* left shifts */
    for( j = 0; j < 4; j++ )
    {
        i = i << 1;   /* left shift i by 1, which is same as a multiply by 2 */
        printf( "Left shift %d: %d/n", j, i );
    }

    return 0;
}

      取反操作符~会把操作数的每一位取反。也就是把1置为0,0置为1。

      位操作符还经常用在加密程序中。比如,需要让硬盘文件变得不直接可读,可以对它们进行一系列位操作。最简单的做法是把每一个字节中的各位都取反。如下:

 Original byte         00101100
 After 1st complement  11010011
 After 2nd complement  00101100

      注意,两次取反后会返回原数值。因此,第一次取反代表对字节进行了编码,第二此相当于解码。如下的函数可以用来对字符编码。

/* A simple cipher function. */
char encode( char ch )
{
    return( ~ch );   /* complement it */
}

      当然,用这个函数加密的文件会很容易破解。

?操作符

      c++中定义了一个非常强大和方便的操作符,它可以替代简单的if-than-else语句。三元操作符?通常使用格式如下:

Exp?Exp2:Exp3;

      其中,exp1、exp2、exp3都是表达式。注意冒号的用法和位置。

      ?操作符的作用是这样的:先检查exp1的值,如果返回true则对exp2求值,反之对exp3求值,这个值将是整个表达式的值。例如:

x = 10;
y = x>9 ? 100 : 200;

      y最终被赋值为100,因为x大于9所以,?前面的表达式返回值为true。如果x的值是小于9的,那么y最终会被赋值为200。如果用if和else写出相同作用的语句,将会是这样:

x = 10;

if( x>9 )
    y = 100;
else
    y = 200;

      我们将在第三章讲述条件语句的时候进一步讲述?操作符。

&和*指针操作符

      指针就是一个对象的内存地址。指针变量则用来存储一个指向某类型对象的指针。获得某些变量的内存地址对于一些特定的程序来说非常有用。指针在c++中的应用主要有三个主要作用:使用它们可以快捷的访问数组对象的某一元素。使用指针使得函数可以对实参进行操作。使用指针可以支持链表等动态数据类型。第五章将会对指针进行专门的介绍。

      首先介绍指针操作符&,这是个一元操作符,用来返回它的操作数的内存地址。如:

m = &count;

      这个语句将变量count的内存地址存入了变量m。你可以把&看作“the address of”。于是上面的赋值语句可以描述为“m获得变量count的地址”。为了进一步理解这个赋值语句,我们先假设count变量在内存中的地址为2000,它的值为100,那么在上面的赋值语句执行后,m将获得的值为2000而不是100。

      下一个要介绍的指针操作符是*,它和&符号刚好互补。*操作符返回的是以随后的操作数为地址的那个变量的值。例如,假定m中存储这count变量的地址:

q = *m;

      这个语句将会把count的值存入变量q。这时q的值应该是100,因为100这个值是存储在地址为2000的变量count中的。*可以看作“at address”。

      不幸的是,乘法操作符(*)和“at address”操作符是一样的,位操作符AND(&)和“address of”操作符是一样的,但是这些操作符本身实际上是没有联系的。&和*指针操作符的优先级都高于普通的算术运算操作符,不过-例外,它们有相同的优先级。

      指针变量必须在声明时加前缀*,这样做是为了告知编译器这个变量用来存储一个指针。例如,要将ch定义为指向字符的指针:

char *ch;

      这里定义的ch不是一个字符变量而是一个指向字符的指针变量,它们是有很大区别的。指针所指向的数据类型,被称为该指针的基类。而指针本身是一个变量,它存储的是一个地址,该地址指向某个数据类型与指针基类相同的变量。因此,指针必须有足够的大小来容纳该计算机体系中的任意地址的长度。不过,有个规则,那就是指针只能指向声明它时所定义的基类的数据类型。

      在同一个声明语句中可以混合指针与非指针变量。如:

int x, *y, count;

      下面的程序利用&和*操作符,完成把数值10赋予变量target的功能。正如预期,程序运行后屏幕上会显示10。程序如下:

#include <stdio.h>

int main( void )
{
    int target, source;
    int *m;
   
    source = 10;
    m = &source;
    target = *m;

    printf( "%d", target );

    return 0;
}

编译时操作符sizeof

      sizeof是一种一元编译时操作符,它的作用是返回变量或者加了括号的类型定义符的字节大小,sizeof是作为前缀使用的。例如,假定某环境下,整型是4个字节,双精度是8个字节:

double f;

printf( "%d", sizeof f );
printf( "%d", sizeof(int) );

这个程序运行之后会显示8 4。

      记住,如果需要获得一个类型定义符对应的类型的大小,那么使用sizeof的时候需要用括号将类型定义符括起来。对于变量来说是否使用括号都无关紧要,当然,用了括号也没有坏处。c++定义了一个特别的数据类型size_t,对应数据类型为整型。所以你可以把size_t这种类型的变量当作整型来处理。sizeof主要用来获取内建数据类型的大小,以用来在不同的环境中移植。假设现在编写一个数据库程序,需要每条记录存储6个变量。而这个数据库要在多个操作系统环境下都能运行,那么你无法确定每一个整型的长度,这时就需要用到sizeof来确定整型的长度。下面的例程演示了如正确的将包含留个整型的记录存入硬盘。

/* Write 6 integers to a disk file. */

void put_rec( int rec[6], FILE *fp )
{
    int len;

    len = fwrite( rec, sizeof(int)*6, 1, fp )
    if( len != 1 )
        printf( "Write error !" );
}

无论在16位还是32位环境下,上面的代码都会运行正常。

需要强调的是,sizeof是在编译时获得数值的操作符,随后在程序中这个获得的数值被当作常量处理。

逗号

      逗号操作符链接多个表达式,逗号左侧的操作数往往是空类型。也就是说,用逗号格开的几个表达式的总值应该等于最右边的那个表达式的值。例如:

x = ( y = 3, y + 1 );

      这个语句执行的时候首先对y赋值为3,然后将c赋值为4。这里的括号是必须的,因为逗号操作符的优先级低于赋值操作符=。

      本质上,逗号操作符导致了一系列的操作按照某一顺序完成。假如,在某一赋值语句的等号右边使用了逗号操作符分开多个表达式,那么最右边的表达式的值会被该赋值语句采用。逗号操作符的意义有些类似于平常说的and,就是“do this and this and this”。

Dot(.)和Arrow(->)操作符

      在C语言中这两个操作符用来访问某一数据结构或者联合的私有元素.在C语言中,结构和联合把多个各种数据类型组合到一个整体中.使用一个总的名称.在c++中,这两个操作符常用来访问类的成员.

      当直接访问结构(structure)或者联合(union)的内部成员时,往往使用Dot. 而当通过指向结构和联合的指针访问其成员时则使用Arrow(->).例如:

struct employee
{
    char name[80];
    int age;
    float wage;
}emp;

struct employee *p = &emp; /* address of emp into p */

当你要对该结构的wage成员赋值为123.23的时候,则需要通过以下方式:

emp.wage = 123.23;

不过,使用指针的方式语句就要写成这样:

p->wage = 123.23;

方括号和圆括号

圆括号可以用来提高它所括的操作式的优先级.方括号则用来展示数组的索引.例如:

#include <stdio.h>

char s[80];

int main( void )
{
    s[3] = 'X';
    printf( "%c", s[3] );

    return 0;
}

      首先将'X'赋值给s数组的第四个元素,然后将这个元素在屏幕上显示.记住,所有的数组都是从下标0开始,所以,s[3]代表的是数组的第四个元素.

优先级概括

      表2-8 列出了所有C语言中定义的操作符的优先级.除了一元操作符和?外,其余的操作符都是从左到右结合的.一元操作符*,&,-和?都是从右到左结合.

注:c++还增加了一些新操作符,将在第二部分中讨论.

表2-8.   C语言操作符的优先级

Highest                   ()  []  ->
                          !  ~  ++  --  (type)  *  &  sizeof
                          *  /  %
                          +  -
                          <<  >>
                          <  <=  >  >=
                          == !=
                          &
                          ^
                          |
                          &&
                          ||
Highest                  
                          ?:
                          =  +=  -=  *=  /=  etc.
Lowest                    ,
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值