#
在使用不同编程语言进行软件联合开发的时候,需要统一函数、变量、数据类型、常量等链接规范,特别是在不同模块之间共享的接口部分,当开发程序库的时候,明确链接规范也是必须遵循的一条规则。
对COM接口及其使用的数据类型来说,是否采用统一的链接规范,对其二进制兼容性和可移植性都没有影响。因为连接规范主要影响到名字改编方案的不同,这样即使接口两端对接口本身的解释不通,只要它们使用一致的成员对齐方式和布局方案、一致的函数调用规范、一致virtual function实现方式,总是就是一致的C++对象模型。并且保证COM组件升级时不改变原来的接口和数据类型定义,则所有方法的运行时绑定都不会存在问题(所有方法的调试都被转换为通过对象指针对vptr和vtable及函数指针的操作,这种间接性不再需要任何方法名即函数名的参与,而接口名和方法名只是为了让客户端的代码能够顺利通过编译,但是连接时就完全不在需要了。)
但是对于定义于普通静态链接库和动态链接库中的全局数据类型、全局函数、全局变量甚至全局常量,它们的连接规范必须在两端保持一致、否则客户程序会出现连接问题。这是因为普通的封装为DLL的函数库或者类库,客户程序在创建使一般都需要与它们的导出库进行连接,除非使用loadlibrary()和getprocaddress()函数对来获得DLL中函数的地址,通用的连接规范要属C连接规范:extern‘C’。
具体使用方法,里仁教育嵌入式培训职业讲师详情讲解:
Extern’C’void WinMainCRTStartup();
Extern’C’const CLSID CLSID_DataConvert();
Extern’C’struct Student{.......};
Extern’C’student g_student;
如果是对一段代码指定连接规范:
#ifdef _cplusplus
Extern ‘C’{
#endif
Const int MAX_AGE=200;
#pragma pack(push,4)
Typedef struct _person
{
Char *m_Name;
Int m_Age;
}person,*personPtr;
#pragma pack(pop)
Person g_Me;
Int _cdecl memcmp(const void*,const void*,size_t);
Void * _cdecl memcpy(void,const void*,size_t);
Void* _cdecl memset(void*,int,size_t);
#ifdef _cplusplus
}
#endif
嵌入式行业资讯:全套基础:
http://www.lirenedu.org/index.php?ack=lanmu&id=82
有些进程在运行时会占用大量的CPU,有些进程会导致X死掉,有些进程会吞噬掉大量的内存,这些进程直接影响了用户的正常工作,最直接的现象就是系统运行缓慢,死机等现象,处理这些进程一般的方法就是结束这个进程,就是所说的把它KILL掉。下面介绍几种消灭进程的方法。
l 使用Kill命令来消灭进程
如果运行了某个程序导致了死机,那么就应该切换到其他的控制台下,按下ctrl+alt+fx,其中x可以是1·5,这取决于用户的try的多少。
用ps显示这个程序的进程ID。
这里以xchat为例。
$ps aux |grep xchat
Wanglin 12063 0.0 1.8 89536 19028 ?S1 apr06 2:40 xchat
其中12063就是它的ID。
也可以使用pgrep来显示ID,如下:
$pgrep xchar
12063
使用Kill来消灭这个进程
使用kil来消灭进程,如果消灭不掉,还要加参数-9,它可以强制结束进程。
$ kill 12063
$ kill -9 12063
l 使用pkill或者killall来消灭进程
它们的共同点就是都可以用程序的名称作为参数。
$ pkill -9 xchat
$ killall xchat
l 使用图形化的方式来消灭进程
$xkill
会出现一个X形的光标,单击需要消灭的窗口,就可以消灭这个程序。www.lirenedu.org
Patch的主要用途就是更新源代码到新的版本,避免下载整个源代码,下载一个有效的补丁仅仅需要下载发生变化的那些代码行就可以了,patch的帮助文档中罗列了众多的用法,其实大多数的时间只要下面两个命令参数就能满足大家的需要。下面讲解patch的用法,以Ubuntu7.10系统为例。
1. 命令格式
#patch -p1<[patchfile]
或者
#patch -R <[patchfile]
上面两个格式任选一条就可以了。
2.使用方法
#patch -p1<[patchfile]
要求补丁文件要放到源代码目录下,然后在运行这条命令。
例如:给xchat2.6.0打补丁, 补丁文件是xc260-fetext.diff。
首先选入 xchat2.6.0的目录, 并且将xc260-fix-fetext.diff文件复制到这个目录,然后运行:
#patch -p1<xc260-fix-fetext.diff
如果出现提示信息:patching file src/text/fe-text/fe-text.c 这说明打补丁成功了。
#patch -R<[pathfile]
这个命令运行后,还要指定被补丁的文件的路径和文件名.www.lirenedu.org
在Ubuntu系统下工作,只掌握图形化的配置工具还是不够的,系统在出现故障的时候往往使用的是终端的操作模式,下面里仁3G培训讲师介绍在终端下如何配置网络。
临时改变网络参数
l .Ifconfig:查看和配置IP地址。
$ifconfig eth0
$sudo ifconfig eth0 192.168.9.23 netmask 255.255.255.0
route:配置路由参数
$sudo route add default gw 192.168.9.1 eth0 #设置默认网关
使参数立即生效
$sudo/etc/init.d/networking restart
修改网络配置文件
设置DNS服务器。
$sudo echo‘nameserver=219.150.32.132>/etc/resolv.conf’
编辑/etc/network/interfaces。
$sudo vim /etc/network/interfaces
Auto lo
Iface lo inet loopback
Iface eth0 inet static #设置eth0,静态IP
Address 192.168.8.45
Netmask 255.255.255.0
Gateway 192.168.8.1
Iface eht1inet dhcp #设置eth1为dhcp模式
l 可以通过下面的命令设置路由。
Up route add default gw 192.168.8.1 eth1
Up route add –net 192.168.8.0/24 gw 192.168.8.1 eth0
Down route del –net 192.168.8.0/24 gw 192.168.8.1 eth0
其中,当网络接口up时,执行它后面的命令;当网络接口down时,执行它后面的命令。
使用参数立即生效。
$sudo /etc/init.d/networking restart 转:www.lirenedu.org
许多学员都使用linux来完成各种工作,包括学习、办公、编程、网络维护等,但对所使用系统的一些基本信息知了甚少,有的连自己显卡的型号、CPU的具体型号、硬盘的使用情况、内存的使用情况网络的使用情况都不清楚,一旦系统出现故障,就无从下手,所以在此里仁3G嵌入式培训讲师有必要给大家介绍如何准确地获得自己的系统信息。
1. 系统信息
l 查看内核信息。 $uname -a
l 查看操作系统的版本。 $head –n 1/etc/issue
l 查看CPU的信息。 $cat /proc/cpuinfo
l 查看计算机名称。 $hostname
l 列出所有PCI设备信息。 $lspci –tv
l 列出所有USB设备信息。 $lsusb –tv
l 列出系统加载的模块信息。 $lsmod
2. 系统资源的使用信息。
l 查看内存和交换区分的使用量。 $free –m
l 查看硬盘分区的使用情况。 $df –h
l 查看某个目录的大小。 $du –sh<目录>
l 查看内存总量和空闲内存量。
$grep memTotal /proc/meminfo
$grep memfree /proc/meminfo
l 查看系统运行时间、用户数和负载。$uptime
l 查看系统负载。$cat /proc/loadavg www.lirenedu.org
编译器无法预期一个程序在执行过程中会在何时创建一些什么对象,而只能根据当时的上下文要求创建,对象的初始化最好能够通过运行时执行一个函数来完成,而且是在对象创建的同时,这个函数就是构造函数,同样,对象在完成其使命的时候能够通过一个函数来销毁,这就是析构函数。
当给一个对象分配好原始内存空间的时候,这个对象就应该算创建起来了。只不过它还处于一种“原始状态”,即末初始化的,不良的状态,如果把这样的内存直接拿来使用,除非第一个操作是赋值,否则极有可能出错。例如:
Long long1; //局部变量
Count<
Char*pstr=(char*)malloc(1024);
Cout<
因此,创建一个变量或动态对象时一定不要忘记初始化。 初始化就是在对象创建的同时使用初值直接填充对象的内存单元,因此,不会有数据类型转换等中间过程,也就不会产生临时对象,而赋值则是在对象创建好后任何时候都可以调用的而且可以多次调用的函数,由于它调用的是“=”运算符,因此可能需要进行类型转换,即会产生临时对象。
C++对象可以使用构造函数来初始化,构造函数是任何对象创建时自动调用的第一个成员函数,也是为每个对象仅调用一次的成员函数,所以构造函数的作用就是:当对象的内存分配好后把它原始状态变成良好的可用的状态。
有的程序员可能认为:虽然我没有在构造函数中初始化数据成员,但是我在声明一个对象后马上调用它的set-XXX()函数来初始化它的每一个成员,效果也是一样的。
最好为每个类显式地定义构造函数和析构函数,即使它们暂时空着,尤其是当类含有指针成员或引用成员的时候。
构造函数的另一重要用途就是给一些可能可能存在的隐含成员如vptr创造一个初始化的机会,否则虚拟机将不能保证实现,每当此时,如果程序员没有为一个多态类显式地定义默认构造函数、拷贝构造函数、析构函数或拷贝赋值函数,那么编译器会自动得生成相应的函数,它们都是public inline的,并在其中插入正确初始化或修改vptr数据成员值的代码,而且确保基类对象和派生类对象构造时及在它们之间拷贝时vptr能够指向或重新指向恰当的vtable,这样的4个函数分布叫非平凡默认构造函数、非平凡拷贝构造函数、非平凡析构函数和非平凡拷贝赋值函数。www.lirenedu.org
与函数堆栈使用密切相关的就是函数调用规范,即调用约定(Calling Convenion)。函数调用规范决定了函数调用的实参压栈、退栈及堆栈释放的方式以及函数名改编的方案,windows环境下常用的调用规范有:
1) _cedcl:这是C++/C函数的默认调用规范,参数从右向左传递压入堆栈,由调用函数复杂堆栈的清退,因此这种方式利于传递个数可变的参数给被调用函数。如printf()就是这样的函数。
2) _stdcall:这是Win API函数使用的调用规范,参数从右向左依次传递并压入堆栈,由被调用函数复杂堆栈的清退。该规范生成的函数代码比_cdecl更小,但当函数有可变个数的参数时会转为_cdecl规范。在Windows中,宏WINAPI、CALLBACK都定义为_stdcall。
3) _thiscall:是C++非静态成员函数的默认调用规范,不能使用个数可变的参数。当调用非静态成员函数的时候,this指针直接保存在ECX寄存器中而压入函数堆栈,其他方面与_stdcall相同。
4) _fastcall:该规范所修饰的函数的实参将被直接传递到CPU寄存器中而不是内存堆栈中,堆栈清退由被调用函数负责,该规范不能用于成员函数。
函数必须制定的一个调用规范,特别是在模块之间的逻辑接口中,每个函数原型的调用规范必须与其实的调用规范保持一致,否则会出现编译连接错误。如果你调用了在某个DLL中实现的COM对象的方法,而这些方法在创建时却没显式地制定调用规范,那么它们会使用环境默认的调用规范,虽然你的程序可以通过编译和连接,但是在运行时就可能导致程序崩溃。
所以,凡是接口函数都必须显式地制定其调用规范,除非接口函数是类的非静态成员函数,如果不显式制定调用规范,类的静态成员函数和全局函数将采用C++/C默认的函数调用规范或者由工程设置指定的调用规范,因此最好也为静态成员函数显式地指定调用规范。
注意:类的静态成员函数的默认调用规范不是thiscall,类的友元函数的调用也不是thiscall,它们都是由函数本身指定或者由工程设定的。COM接口的方法都指定_stdcall调用规范,而我们自己开发COM对象及接口时也可以指定其他的调用规范。
一定要知道C基础的基本概念:
认识函数堆栈:http://www.lirenedu.org/index.php?ack=xinwen&id=1026
基于C语言基础概念:http://www.lirenedu.org/index.php?ack=xinwen&id=1024
操作系统几个基本要点:http://www.lirenedu.org/index.php?ack=xinwen&id=1029
一、可默认构造的,也即具有public的default constructor,不论是用户显式定义还是编译器默认的,但是用户定义的带参数constructor会仰制编译器合成default constructor,实际上并非任何情况下任意一种容器要求其元素类型满足这一条件,特别是关联式容器,因为只有序列式容器的某些函数才可能明确地或隐含地使用元素类型的default constructor,如果你不调用这样的成员函数,编译器就不需要元素类型的默认构造函数。
二、可拷贝构造和拷贝赋值的,既具有public的copy constructor和copy assignment operator,不论是编译器默认还是operator,如果没有显式定义它的话,这个条件可归结为:元素必须是拷贝的,但实际上拷贝赋值的要求也不是强制的,原因和default constructor类似。
三、具有public的destructor,不论是编译器默认的还是用户显式定义的。
四、对于关联式容器,要求其元素必须是可比较的。
Auto_ptr满足上述条件吗?至少满足前三条,因此至少可以作为序列式容器的元素,如果为auto-ptr定义了比较运算符的话,应该还可以把它作为关联式容器的元素。
但是auto_ptr的特点是接管和转移拥有权,而不是像原始指针那样可以共享实值对象,即auto_ptr在初始化时接管实值对象和拥有权,而在拷贝时会交出实值对象及其拥有权。
因此,auto_ptr对象和它的拷贝不会共享实值它的拷贝并不相同,然而根据STL容器值语义的要求,可拷贝构造意味着一个着把一个对象赋值给另一个同类型对象将产生两个相同的对象,显然,auto_ptr不能满足这一要求,与上面结论矛盾!那么问题出在哪里呢?
在揭开auto_ptr的之前需要了解copy constructor和copy assignment operator,的几种合法形式,任何一个类都允许两种形式的copy constructor:
C(const C©);
C(C©);
同样,copy assignment operator允许类似的两种形式。
C& operator=(const C ©);
C& operator=(C & copy);
实际上,由于copy assignment operator为普通的运算符重载成员函数,因此还可以定义下列形式赋值函数;
C&operator=(C copy);
如果要防止用户把一些不合适的对象放入容器中,就要求对象的设计和是实现者使用一些语言支持但不常用的特征,也就是说,要能够在编译阶段就阻止这种具有潜在危险性的行为,常用的方法就是迫使其违反C++静态类型安全规则。
源处:
http://www.lirenedu.org/index.php?ack=xinwen&id=1178
传统的错误处理是用不同的数值来表示不同类型的错误,其表达能力很有限,因为一个数字包含的信息量太少,而C++异常处理机制将异常类型化,显然一个类型要比一个数字包含的信息量大得多。
比如我们常用的函数fopen(),当打开文件失败是返回NULL,按照传统的错误处理方法,在调用Fopen()后立即检查其返回值,如果为NULL就进行错误处理,如果将返回NULL改为抛出异常OpenFailed,那么我们就不用在调用fopen()后马上检查返回值,而是在调用函数内部或者更高层的调用者那里设置异常处理器来捕获这个异常,C++保证:如果一个异常在抛出点没有得到处理,那么它将一直抛向上层调用者,直至main()函数,直到找到一个类型匹配的异常处理器,否则调用terminate()结束程序。
可以看出:异常处理机制实际上是一种运行时通知机制。
Class DevidedByZero{};
Double Devide(double a,double b)
{
If(abs(b)::numeric_limits::epsilon())
{
Throw DevidedByZero();//提前检测异常发生条件并抛出自定义异常
Return a/b; //这才是可能真正发出错误的地方
}
Void test()
{
Double x=100,y=20.5
Try{
Cout<抛出异常DevidedByZero
}
Catch(DevidedByZero&){
Cerr<< “ Devided by zero!”<
}
}
如果在申请动态内存时找不到足够大的连续字节内存块,malloc()和new()会使用不同的方式宣告内存申请失败,通常有如下几种方式处理“内存耗尽”问题:
1. 判断指针是否为NULL,如果是则立刻用return语句终止本函数。例如:
Void Func(void)
{
A *a=new(nothrow) A;
If(a==NULL)return;
……
}
2. 判断指针是否为NULL,如果是则立刻用exit(1)终止整个程序的运行,例如:
Void Func(void)
{
A *a=new(nothrow) A;
If(a==NULL)exit(1);
}
3. 为new和malloc()预设异常处理函数,例如,Visual C++可以用_set_new_hander函数为new设置用户自定义异常处理函数,也可以让malloc()享用与new相同的异常处理函数。
4. 捕获new抛出的异常,并尝试从中恢复。
上述(1)和(2)两种方式使用最普通。如果一个函数内有多处需要动态申请内存,那么方式(1)就显得力不从心,应该用方式(2)来处理。不过在C++中我们提倡使用方式(4)。
有一个很重要的现象要告诉大家:
对于32位以上的应用程序而言,一般情况下使用malloc()和new几乎不可能导致‘内存耗尽’。我在windows98下用Visual C++编写了测试程序:
这个程序无休地运行下去,根本不会终止,因为32位操作系统支持‘虚存’,内存用完了,自动用硬件空间顶替。
Void main()
{
Int *p=NULL;
Unsigned int len=1024*1024;
While(1){
P=new(nothrow) int[len]; //或者 malloc(sizeof(int)*len);
If(!p){
Len>>=1; //len缩小一半
If(len==0)
Exit(1);
Continue;
}
Cout<<“Allocated:”<<“(len*sizeof(int))”<<“bytes.”<<endl;
}
}
可以得出一个结论:
对于32位以上应用程序,内存耗尽错误处理程序几乎毫无用处,但是必须强调不加错误处理将导致程序的质量很差,千万不可因小失大。