理解const char * const *等修饰符

来源:互联网 发布:软件项目验收方案 编辑:程序博客网 时间:2024/05/17 12:52

首先上代码

const char* const tag_9500[] = {//"1/8=Data authentication was not performed",//"1/7=Static Data Authentication failed", //"1/6=ICC data missing", //"1/5=Card appears on terminal exception file", //"1/4=Dynamic Data Authentication Failed", //"1/3=Combined Data Authentication Failed", //"1/2=SDA Selected", //"1/1=RFU", //"2/8=ICC and terminal have different application versions", //"2/7=Expired application", //"2/6=Application not yet effective", //"2/5=Requested service not allowed for card product", //"2/4=New card", //"2/3=RFU", //"2/2=RFU", //"2/1=RFU", //"3/8=Cardholder verification was not successful", //"3/7=Unrecognised CVM", //"3/6=PIN try limit exceeded", //"3/5=PIN entry required, no PIN pad", //"3/4=PIN entry required, no PIN", //"3/3=Online PIN entered", //"3/2=RFU", //"3/1=RFU", //"4/8=Transaction exceeds floor limit", //"4/7=Lower consecutive offline limit exceeded", //"4/6=Upper consecutive offline limit exceeded", //"4/5=Transaction selected randomly for online processing", //"4/4=Merchant forced transaction online", //"4/3=RFU", //"4/2=RFU", //"4/1=RFU", //"5/8=Default TDOL used", //"5/7=Issuer authentication was unsuccessful", //"5/6=Script processing failed before final Generate AC", //"5/5=Script processing failed after final Generate AC", //"5/4=RFU", //"5/3=RFU", //"5/2=RFU", //"5/1=RFU", };const char * const tag_9B00[] = {"1/8=Offline data authentication was performed", //"1/7=Cardholder verification was performed", //"1/6=Card risk management was performed", //"1/5=Issuer authentication was performed", //"1/4=Terminal risk management was performed", //"1/3=Issuer script processing was performed", "1/2=RFU", //"1/1=RFU", //"2/8=RFU", //"2/7=RFU", //"2/6=RFU", //"2/5=RFU", //"2/4=RFU", //"2/3=RFU", //"2/2=RFU", //"2/1=RFU", };void DumpBit(const char * const *ppszTagDesc, UCHAR *pucTagValue, UINT uiTagLen) {UINT i, j;ppszTagDesc = (const char**) ppszTagDesc;for (i = 0; i < uiTagLen; i++) {for (j = 8; j > 0; j--) {if ((pucTagValue[i] & (1 << (j - 1))) == 0)continue;printf("\r\n#    Byte %d Bit %d %s", i + 1, j,ppszTagDesc[i * 8 + (8 - j)]);}}printf("\r\n");}void EMVTAG_DumpBits(USHORT usTag, UCHAR *pucTagValue, UINT uiTagLen) {switch (usTag) {case 0x9500: //TVRDumpBit(tag_9500, pucTagValue, uiTagLen);break;case 0x9B00: //TSIDumpBit(tag_9B00, pucTagValue, uiTagLen);break;}}


C++的规定

4.4 Qualification conversions

A conversion can add cv-qualifiers at levels other than the first in multi-level pointers, subject to the following rules:51)

Two pointer types T1 and T2 are similar if there exists a type T and integer n > 0 such that:

T1 is cv1 , 0 pointer to cv1 , 1 pointer to . . . cv1 ,n − 1 pointer to cv1 ,n T

and

T2 is cv2 , 0 pointer to cv2 , 1 pointer to . . . cv2 ,n − 1 pointer to cv2 ,n T

where each cvi, j is const, volatile, const volatile, or nothing. The n-tuple of cv-qualifiers after the first in a pointer type, e.g., cv1 , 1 , cv1 , 2 , . . . , cv1 ,n in the pointer type T1, is called the cvqualification signature of the pointer type. An expression of type T1 can be converted to type T2 if and only if the following conditions are satisfied:

— the pointer types are similar.
— for every j > 0, if const is in cv1 , j then const is in cv2 , j, and similarly for volatile.
— if the cv1 , j and cv2 , j are different, then const is in every cv2 ,k for 0 < k < j.

当cv1,j和cv2,j不相同的时候,只要处于0--j之间的指针都有const修饰,那么就是合法的。

问题就是因为cv1,1和cv1,2不同,但cv2,0有const,所以可以转换。类似地,如下这些情况在C++中都可以转换:

char *** 和 const char * const * const *;
char **** 和 const char * const * const * const *;

但如下情况不能转换:

char *** 和 const char * * const *或者 const char * const ** 等等

如何理解

理解的关键将char**作为(char*)*对待,然后看const修饰的对象 http://bbs.csdn.net/topics/370237704

明确const修饰的对象,如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。

C++ 对于指针p1,和p2,若要使得p2=p1成立,则可读做 :
“p1是指向X类型的指针,p2是指向“带有const限定”的X类型的指针 “。 
char *p1;const *p2=p1;//合法:p1是指向(char)类型的指针,p2是指向“带有const限定"的(char)类型的指针。

        char **p1;const  char**p2=p1;//不合法:p1是指向(char*)类型的指针,p2是指向 ((const char)*)类型的指针。

        char **p1;char const**p2=p1;//不合法;与上等价。

        char**p1;char*const*p2=p1;//合法:  p1是指向(char *)类型的指针,p2是指向“带有const限定"的(char*)类型的指针。

这是C++语法规则,在C中因为char **可以转换为const char**


可以记忆的声明

const char *p; //*pconst,p可变

const (char *) p;//pconst,*p可变

char* const p; //pconst,*p可变

const char* const p; //p*p都是const 


char const * p;// *pconst,p可变

(char*) const p;//pconst,*p可变

char* const p;// pconst,*p可变

char const* const p;// p*p都是const


记忆方法
转自http://blog.csdn.net/swibyn/article/details/20052371
The C++ Programming Language里面给出过一个助记的方法:

把一个声明从右向左读。

char * const cp; ( * 读成 pointer to) cp is a const pointer to char

const char * p; p is a pointer to constchar;

char const * p; 同上因为C++里面没有const*的运算符,所以const只能属于前面的类型。

奇技淫巧:

方法也是从右向左一步一步来解释,而且每一步都有返回值,是的你没看错,有返回值。每一步都相当于一个函数,上一步的返回值即是下一步的入参。

const char *p;来说吧

1,“p”:代表内存的一块空间,暂且称为”内存1”, 返回值当然是p了,也就是内存1。

2, “*” :当p被星了之后,就跳到新的内存位置,也就是“内存2”。 内存2就是我们说的*p, 这时返回值就是内存2。

3,“char”: 因为上一步的返回值是内存2,所以这个char就作用在内存2上,就像是在说这里存的是一个char类型数据。 返回值还是内存2。

4,“const” :上一步返回内存2(具有char特点的内存2),这时const就作用在内存2上,结果就是说内存2不能变了,他是常量。返回值还是内存2(具有char特点和const特点的内存2)。

5,如果前面还有修饰符,应该可以这样再推下去(起码我是这么想的^-^)

6,前面的都解释完了,不是吗

 

再来看个例子:

const (char *) p;

1, “p”:代表内存的一块空间,称为”内存1”,返回值当然是p,也就是内存1。

2, “(char*)”: 整个修饰p,因为不是*,不会跳转到新的内存,所以返回值还是p,还是内存1。

那“(char* )”什么意思呢,他相当于是一个自定义类型,就像一个自定义函数,简称大函数,由两个小函数构成。

函数1是“*”,函数2是“char”。

函数1“*”的处理结果是跳到另一块内存,即内存2,返回值是内存2。

函数2“char”的处理结果是说内存2是char类型,返回值是内存2。

只可惜这个返回值被大函数隔离了,大函数作为一个整体返回的是入参的那块内存。

如果有一天这个大函数只有一个小函数,这个小函数是“*”,即大函数数“(*)”,这时别以为“*”和“(*)”有什么区别,就是差个马夹而已。

3,“const”:修饰上一步返回的内存,即内存1

 

注意:不要被这里的内存1,内存2诱导,我可没说给他们开辟空间了,声明时是不开辟空间的。

只有在实际赋值之后,内存1,内存2才有对应的实际的内存空间。

所以声明,只是在使用之前先描述一下这个变量具有什么特点,如何来使用这个变量而已。

所以不管是说内存1是const,或内存2是const,并不是说实际的那块内存真的就不能改了(实际上也做不到)。

这里对声明的变量赋值实际上是提供了对某块内存访问的一个方法。Const,char都是描述了这个方法的一些特点;而“*”的作用是跳转到另一块内存。


原创粉丝点击