随笔 - 78  文章 - 1  trackbacks - 0
<2024年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

常用链接

留言簿(1)

随笔分类

随笔档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜

http://www.tyut.edu.cn/kecheng1/site01/suanfayanshi/
posted @ 2012-12-05 22:14 Carrie 阅读(173) | 评论 (0)编辑 收藏

char ** 和const char**引发的思考。。。  

2007-05-10 09:05:39|  分类: 2007-05 |  标签:get   |字号 订阅

foo(const char **p){}
main(int argc, char **argv)
{
   foo(argv);   //error
}
在vc6.0中会报以下错误:
error C2664: 'foo' : cannot convert parameter 1 from 'char ** ' to 'const char ** '


首先明确一下char * const、const char *和char * 的区别:


char * const 指向字符的静态指针,即const pointer to char
const char * 指向静态字符的指针,即pointer to const char
char *  指向字符的指针,即pointer to char


三个最大的区别是什么可以改变,什么不能改变。


很明显,第一种“指针”是不能变的,但是指针所指向的值can be changed,because the pointer is const type;
第二种指针可以变,但是针所指向的值can't be changed,because the char is const type,the pointer isnot;
那么第三种呢?其实第三种和第一种是一样的,默认char * 即为char * const,所以平时很少见到有写成char * const。


明确了三者的区别我们再来看一个例子:
char *cp;
const char * ccp;
ccp = cp;


1)  左操作数ccp是指向 有const限定符的char 类型 的指针。
2)  右操作数cp 是指向  无限定符的char 类型 的指针。
3)  显然char类型和char类型是相容的,ccp 所指向的类型具有cp所指向类型的限定符(无) 和自身的限定符const.


所以 ccp = cp 是合法的,相反 cp = ccp 就会警告

现在再回头看之前的问题:
const char** 是一个没有限定符的指针类型,它的类型是"指向有const限定符的char类型的指针的指针"。
而char ** 的类型是“指向char类型的指针的指针”


char ** 和 const char ** 都是没有限定符的指针类型,但它们所指向的类型不一样( 前者指向char*, 后者指向 const char*), 因此它们是不相容的。

根据ANSI C标准:要使赋值形式合法,必须满足下列条件之一:


1、两个操作数都是指向有限定符或无限定符的相容类型的指针;
2、左边的指针所指向的类型必须具有右边指针所指向类型的全部限定符。


所以之前的那个函数调用的形参的赋值是错误的,编译不过也是正常的。。。


所有这些问题都与一个东西有关,那就是“const”,const到底妙处在什么地方呢???


下面引用在《c编程专家》中的原话:

关键字const并不能把变量变成常量!在一个符号前加上const限定符只是表示这个符号不能被赋值,也就是它的值对于这个符号来说是只读的,但它并不能防止通过程序的内部(甚至外部)的方法来修改这个值,const最有用指出就是它来限定函数的形参,这样该函数将不会修改实参指针所指的数据,但其他的函数却可能会修改它。这也许就是c和c++中const最一般的用法。
const和*的组合通常只用于在数组形式的参数中模拟传值调用。它声称:“我给你一个指向它的指针,但你不能修改它”,这个约定类似于极为常见的void *的用法,尽管在理论上它可以用于任何情形,但通常被限制于把指针从一种类型转换为另一种类型。
const关键字原先如果命名为readonly就好多了。。。

posted @ 2011-10-31 20:05 Carrie 阅读(1929) | 评论 (1)编辑 收藏
     摘要: 动态数组,顾名思义,就是可以动态分配长度的数组。在c语言中,数组的长度是固定的,而这种限制显然是很不灵活的。在c++中,数组有时候不用在编译时就知道长度,直到运行时才知道。与普通的数组变量不同,动态分配的数组将一直存在,直到程序显式的释放它为止。  阅读全文
posted @ 2011-06-10 21:57 Carrie 阅读(205) | 评论 (0)编辑 收藏
     摘要: 一、非引用形参

void add1(int v1)
{
v1+=1;
}

这是最普通的形参方式,当函数被调用时,实参的副本初始化形参,函数并没有访问调用所传递的实参,因此v1+=1不会修改实参的值。对v1的操作只是修改了实参的一个副本。  阅读全文
posted @ 2011-06-10 21:56 Carrie 阅读(265) | 评论 (0)编辑 收藏
     摘要: 这个要不是看PIC的编程说明,还真不知道有这种结构,孤陋寡闻啊,网上查了一下,转载一些基础说明文档。

位域

  有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:
  阅读全文
posted @ 2011-06-10 21:48 Carrie 阅读(388) | 评论 (0)编辑 收藏
     摘要: 1.直接声明结构体变量:

struct{
int length;
int width;
}box1;

这样就声明了一个名为box1的结构体变量,但是同时要注意,如果在同一个程序中还存在如下的声明:

struct{
int length;
int width;
}box2;

请千万不要认为这个时候box1和box2是两个相同类型的变量,如果你尝试将box1赋值给box2,你将会发现编译器会给你一个错误提示:incompatible types in assignment ,说明两个两个变量的类型是不同的

  阅读全文
posted @ 2011-06-10 21:46 Carrie 阅读(348) | 评论 (0)编辑 收藏
     摘要: struct多种声明定义写法的小结详细讲解struct这个容易混淆的写法的书是有的,《C专家编程》中就有详细的描述。可惜大家喜欢问问题有甚于喜欢看书,于是BBS上泛滥着前人早已经解决、说明清楚的问题。哎,中国勤学好问者的悲哀。这里简要说明一下struct,为大家省钱。
  阅读全文
posted @ 2011-06-01 20:43 Carrie 阅读(503) | 评论 (0)编辑 收藏
错误 LNK1120 为您提供该链接的无法解析的外部对象数 (number)。导致无法解析的外部对象的条件由错误 LNK2001 描述,此错误出现在该错误信息之前(对每个无法解析的外部对象都出现一次)。 //就是说每出现一次LNK1120都会在之前出现一个LNK2001 所以主要是解决LNK1120关键是要解决链接器工具错误 LNK2001 这分一下的情况(来自VS 2008的帮助),在这里我只复制一些比较常见的,如果还不行,你重建工程来吧~~
 
一、代码问题
1.如果 LNK2001 诊断文本报告 __check_commonlanguageruntime_version 是无法解析的外部符号,在 function 中找到了未定义的外部符号 (symbol)。若要解决此错误,请提供符号定义或移除引用它的代码。
2.成员模板的定义超出了类的范围。Visual C++ 的一个限制是,成员模板的定义必须完全位于封闭类内。
3.代码中大小写不匹配
4.如果项目使用函数内联,但在 .cpp 文件而非头文件中定义函数,则会导致 LNK2001。
5.试图引用没有外部链接的函数或数据会导致 LNK2001。
6.缺少函数主体或变量会导致 LNK2001。
7.调用参数类型与函数声明中的参数类型不匹配的函数会导致 LNK2001。名称修饰将函数参数合并到最终修饰函数名中。
8.错误包含的原型导致编译器需要没有提供的函数体,这样会导致 LNK2001。如果同时具有函数 F 的类实现和非类实现,请注意 C++ 范围解析规则。
9.在使用 C++ 时,将函数原型包含在类定义中但未能包含实现(该类的此函数的实现)会导致 LNK2001。
10.试图从抽象基类的构造函数或析构函数调用纯虚函数会导致 LNK2001。纯虚函数没有基类实现。
11.试图在函数范围外使用用该函数声明的变量(局部变量)会导致 LNK2001。
 
二、编译和链接问题
1.项目缺少对库 (.LIB) 或对象 (.OBJ) 文件的引用。有关更多信息,请参见用作链接器输入的 .lib 文件。
2.如果使用 /NODEFAULTLIB 或 /Zl,包含所需代码的库将不会链接到项目,除非已显式地包括了这些库。(在使用 /clr 或 /clr:pure 进行编译时,您将看到对 .cctor 的引用;有关更多信息,请参见 混合程序集的初始化。)
3.如果正在使用 Unicode 和 MFC,如果没有创建 wWinMainCRTStartup 的入口点,将在 _WinMain@16 上得到无法解析的外部对象;请使用 /ENTRY。请参见 Unicode 编程摘要。
4.将用 /MT 编译的代码与库 LIBC.lib 链接会在 _beginthread、_beginthreadex、_endthread 和 _endthreadex 上导致 LNK2001。
5.链接需要多线程库的代码(任何 MFC 代码或用 /MT 编译的代码)会在 _beginthread、_beginthreadex、_endthread 和 _endthreadex 上导致 LNK2001。有关更多信息,请参见下列知识库文章:
6.在用 /MD 进行编译时,因为所有的运行时现在都存放在一个 DLL 中,所以源中的“func”引用在对象中变为“__imp__func”引用。如果试图与 LIBC.lib 或 LIBCMT.lib 静态库链接,则将在 __imp__func 上得到 LNK2001。当不用 /MD 进行编译时,如果试图与 MSVCxx.lib 链接,则并非总是得到 LNK2001,但可能会有其他问题。
7.在生成应用程序的调试版本时与发布模式库链接会导致 LNK2001。同样,使用 /Mxd 选项(/MTd 或 /MDd)和/或定义 _DEBUG,然后再与版本库链接,将可能会产生无法解析的外部对象(同时还会出现其他问题)。将发布模式生成与调试库链接同样会导致类似问题。
8.将 Microsoft 库版本和编译器产品版本混合可能会有问题。新编译器版本的库可能包含早期版本的库中没有的新符号。可能需要更改搜索路径中的目录顺序,或将它们更改为指向当前版本。
9.使用库文件选择下的“工具”|“选项”|“项目”|“VC++ 目录”对话框,可以更改搜索顺序。项目的“属性页”对话框中的“链接器”文件夹可能也包含可能已过期的路径。
10.当安装了新的 SDK(可能在不同的位置),但没有将搜索顺序更新为指向新位置时,可能会出现此问题。通常情况下,应将新 SDK 的 include 目录和 lib 目录的路径放在默认 Visual C++ 位置的前面。另外,包含嵌入路径的项目可能仍然指向旧路径,这些路径是有效的,但对于安装到不同位置的新版本所添加的新功能已过期。
11.编译器供应商之间、甚至同一编译器的不同版本之间当前没有 C++ 命名标准。因此,链接用其他编译器编译的对象文件可能无法生成相同的命名方案,从而导致错误 LNK2001。
12.在不同模块上混合内联和非内联编译选项会导致 LNK2001。如果创建 C++ 库时打开了函数内联(/Ob1 或 /Ob2),但描述函数的相应头文件的内联是关闭的(没有 inline 关键字),则将发生此错误。若要防止此问题,请在要包含到其他文件中的头文件中用 inline 定义内联函数。
13.如果使用 #pragma inline_depth 编译器指令,请确保具有 设置为 2 或更大的值,并确保使用 /Ob1 或 /Ob2 编译器选项。
14.在创建纯资源 DLL 时省略 LINK 选项 /NOENTRY 将导致 LNK2001。
15.使用不正确的 /SUBSYSTEM 或 /ENTRY 设置会导致 LNK2001。例如,如果编写基于字符的应用程序(控制台应用程序)并指定 /SUBSYSTEM:WINDOWS,您将得到无法解析的 WinMain 外部对象。有关这些选项和入口点的更多信息,请参见 /SUBSYSTEM 和 /ENTRY 链接器选项。
posted @ 2011-05-24 00:29 Carrie 阅读(3906) | 评论 (0)编辑 收藏

试题1:请写一个C函数,若处理器是Big_endian的,则返回0;若是Little_endian的,则返回1

解答:


剖析:
嵌入式系统开发者应该对Little-endian和Big-endian模式非常了解。采用Little-endian模式的CPU对操作数的存放方

式是从低字节到高字节,而Big-endian模式对操作数的存放方式是从高字节到低字节。例如,16bit宽的数0x1234在

Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
内存地址    存放内容
0x4000       0x34
0x4001       0x12
而在Big-endian模式CPU内存中的存放方式则为:
内存地址    存放内容
0x4000      0x12
0x4001      0x34
32bit宽的数0x12345678在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
内存地址    存放内容
0x4000      0x78
0x4001      0x56
0x4002      0x34
0x4003      0x12
而在Big-endian模式CPU内存中的存放方式则为:
内存地址    存放内容
0x4000      0x12
0x4001      0x34    
0x4002      0x56
0x4003      0x78

union结构的存储方式是共享内存型,一般机器中int是4个字节,char是1个字节,故union的大小为4个字节(详见本博客另一文章http://hi.baidu.com/haoyuewuwei/blog/item/f2896117fdab1f4d21a4e960.html

故,当给union结构中的int赋值为1的时候,若机器是大端模式则存储的值应为:

0x4000      0x00
0x4001      0x00    
0x4002      0x00
0x4003      0x01

若为小端模式则存储的值为:

0x4000      0x01
0x4001      0x00    
0x4002      0x00
0x4003      0x00

而char只占一个字节,其地址为0x4000,由此输出char的值即可知道机器是大端模式还是小段模式。





另一篇

大端格式:

在这种格式中,字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中,如图2.1所示:

 

小端格式:

与大端存储格式相反,在小端存储格式中,低地址中存放的是字数据的低字节,高地址存放的是字数据的高字节。如图2.2所示:

 

 请写一个C函数,若处理器是Big_endian的,则返回0;若是Little_endian的,则返回1

解答:

int checkCPU( )

{

    {

           union w

           {  

                  int a;

                  char b;

           } c;

           c.a = 1;

           return(c.b ==1);

    }

}

剖析:

嵌入式系统开发者应该对Little-endianBig-endian模式非常了解。例如,16bit宽的数0x1234Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

内存地址

0x4000

0x4001

存放内容

0x34

0x12

而在Big-endian模式CPU内存中的存放方式则为:

内存地址

0x4000

0x4001

存放内容

0x12

0x34

 

32bit宽的数0x12345678Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:

内存地址

0x4000

0x4001

0x4002

0x4003

存放内容

0x78

0x56

0x34

0x12

而在Big-endian模式CPU内存中的存放方式则为:

内存地址

0x4000

0x4001

0x4002

0x4003

存放内容

0x12

0x34

0x56

0x78

联合体union的存放顺序是所有成员都从低地址开始存放。

=============== 呵呵 还是附上 另一段代码吧,摘自一个开源项目 ====

int  big_endian (void)

     {
       union{
          long l;
          char c[sizeof(long)];
       }u;
 
       u.l = 1;
       return  (u.c[sizeof(long) - 1] == 1);
     }
  

 

有时候,用C语言写程序时需要知道是大端模式还是小端模式。 所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。例如一个16bit的short型x,在内存中的地址为0x0010,x的值为0x1122,那么0x11为高字节,0x22为低字节。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。我们常用的X86结构是小端模式,而KEIL C51则为大端模式。很多的ARM,DSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式还是小端模式。
 
下面这段代码可以用来测试一下你的编译器是大端模式还是小端模式:
 
short int x;

char x0,x1;

x=0x1122;

x0=((char*)&x)[0];  //低地址单元
x1=((char*)&x)[1];  //高地址单元

若x0=0x11,则是大端; 若x0=0x22,则是小端......


posted @ 2011-05-23 22:31 Carrie 阅读(267) | 评论 (0)编辑 收藏
今天心情比较郁闷。
上班的时候又在那反复的做操作工。
我一点也不喜欢这样的状态,而且觉得自己很危险。
一有时间就要学习。
我缺的知识实在太多了。

郁闷郁闷的,就在跟PB聊天了,聊着聊着,我很想问他结婚了没有,忍了很久没问,结果他先问我了,结婚了没?
其实还是挺喜欢他的,可惜啊。
posted @ 2011-05-23 22:11 Carrie 阅读(79) | 评论 (0)编辑 收藏
仅列出标题
共8页: 1 2 3 4 5 6 7 8