Expert C Programming (Page 19)衍生出的思考总结

一、赋值时带限定符问题(qualifier)

修饰符包括 const, static, ...

挑战你的极限,你看看哪些赋值编译器会报错/警告?

 

左值类型 右值类型 可否赋值 解释
       
普通类型之间赋值      
char const char  
const char 任何异己char  
       
指针类型之间赋值      
char * const char *  
char * char * const  
char * const char * const  
const char * char *  
const char * char * const  
const char * const char * const  
char ** char * const *  
char ** char * const * const  
char ** const char **  
char ** const char * const *  
char ** const char * const * const  
char ** char ** const  
const char ** char **  
const char ** char * const *  
const char ** char * const * const  
const char ** const char * const *  
const char ** const char * const * const  
const char ** char ** const  
const char ** const char ** const  
char * const * char **  
char * const * const char **  
char * const * char * const * const  
char * const * const char * const *  
char * const * const char * const * const  
char * const * const char ** const  
char * const * char ** const  
(const) char * (const) * const 任何异己指针  

 

如果没有清楚,请查询ISO C具体章节,仔细体味。

char * const * char **

1. 对于普通类型赋值: 规则很简单

2. 对于指针类型赋值:

image

补充:如果右边指针指向的类型不带限定符,左边指针指向的类型可以多加修饰符,如:

const char * char *
char * const * char **
const char * const * const char **

 

二、赋值时符号与无符号类型问题

 

三、文字量、变量取地址的类型问题

变量/常量取地址:

是一个const指针类型,此指针不允许再指向其他地址。

注意:变量和常量都是需要分配存储空间的,只是其值是否只读这种限定的区别而已。

很简单的测试:

#include <stdio.h>
 
int main()
{
    int i=0;
    int j=1;
    &i=&j;
 
    return 0;
}

编译错误: 无效的左值

&i的类型应该为int * const
#include <stdio.h>
 
int main()
{
    const int i=0;
    ++*(&i);
 
    return 0;
}

编译错误。

&i的类型应该是const int * const

 

文字量取地址:

一般来说,内建类型的文字量都是编译时直接计算出来,表现在汇编级别就是"立即数"(immi )。于是它们不存在地址的问题。这些文字量包括比如1, 1.23以及宏展开,它们是不占用存储空间。

于是,对上述文字量取地址是非法的. 即&操作符不允许应用到上述的文字量。你试试:

#include <stdio.h>
 
int main()
{
    int * ptr = &0;
 
    return 0;
}

编译通不过:invalid lvalue in unary `&'  

 

但是唯一可以取地址操作的文字量是:字符串!

#include <stdio.h>
 
int main()
{
    char * ptr = (char *)&("this is a string");
 
    return 0;
}

OK, 编译没问题!

其中,

char * ptr = &("this is a string");
等价于
char * ptr = "this is a string";
C语言在语言层面在做了上述简化的等价保证

字符串文字量是占存储空间的,它们一般分配到只读区,因此对它们取地址的类型应该是const char * const. 依照第一部分的总结,此地址可以赋给char *或者const  char *

测试:

#include <stdio.h>
 
int main()
{
    char * ptr = (char *)&("this is a string");
 
    *ptr = 'r';
 
    printf("%c", *ptr);
 
    return 0;
}

编译可以通过?!

没什么好奇怪的!因为编译期是静态类型检查,ptr的静态类型是char *,但是实际上它指向的是const char, 所以它骗过了编译器。编译器可够愚蠢了:)

但是,罪犯会逍遥于法外吗?不会

果不其然,运行时事发东窗了,运行时异常出错!

像上面的错误,如果刚开始就写成

const char * ptr = (char *)&("this is a string");

那么,在编译期就可以报错!

同样结果也出现在:

#include <stdio.h>
 
int main()
{
    char * ptr = "this is a string";
 
    *ptr = 'r';
 
    printf("%c", *ptr);
 
    return 0;
}

总结:

1. 明确搞清楚取地址后的文字量、常量、变量的类型,当将它们赋给其他指针时,此指针类型最好写明确,以避免出现编译器正确,运行时却报错的问题

2

 

本文中总结赋值时一些类型的问题,在函数参数传递中用到这些规则。请见http://www.cnblogs.com/chio/archive/2008/09/21/1295082.html

posted @ 2008-09-19 15:34  中土  阅读(1149)  评论(0编辑  收藏  举报
©2005-2008 Suprasoft Inc., All right reserved.