??xml version="1.0" encoding="utf-8" standalone="yes"?> C计算Z内存I间都是按照byte划分的,从理Z讲似乎对Mcd的变量的讉K可以从Q何地址开始,但实际情冉|在访问特定类型变量的时候经常在?定的内存地址讉KQ这需要各U类型数据按照一定的规则在空间上排列Q而不是顺序的一个接一个的排放Q这是寚w?br> 寚w的作用和原因Q各个硬件^台对存储I间的处理上有很大的不同。一些^台对某些特定cd的数据只能从某些特定地址开始存取。比如有些架构的CPU在访?一个没有进行对齐的变量的时候会发生错误,那么在这U架构下~程必须保证字节寚w.其他q_可能没有q种情况Q但是最常见的是如果不按照适合其^台要求对 数据存放q行寚wQ会在存取效率上带来损失。比如有些^台每ơ读都是从偶地址开始,如果一个int型(假设?2位系l)如果存放在偶地址开始的地方Q那 么一个读周期可以读32bitQ而如果存攑֜奇地址开始的地方Q就需?个读周期Qƈ对两ơ读出的l果的高低字节进行拼凑才能得到该32bit?据。显然在d效率上下降很多?/p>
先让我们看几个例子吧(32bit,x86环境,gcc~译?: l构体A中包含了4字节长度的int一个,1字节长度的char一个和2字节长度的short型数据一?B也一?按理说A,B大小应该都是7字节?br>之所以出C面的l果是因为编译器要对数据成员在空间上q行寚w。上面是按照~译器的默认讄q行寚w的结?那么我们是不是可以改变编译器的这U默认对齐设|呢,当然可以.例如: 先让我们看四个重要的基本概念Q?br>1.数据cd自n的对齐| 1.在VC IDE中,可以q样修改Q[Project]|[Settings],c/c++选项卡Category的Code Generation选项的Struct Member Alignment中修改,默认?字节?br>2.在编码时Q可以这样动态修改:#pragma pack .注意:是pragma而不是progma. 代码中关于对齐的隐患Q很多是隐式的。比如在强制cd转换的时候。例如: p=&i; 如果出现寚w或者赋值问题首先查?br>1. ~译器的big little端设|?br>2. 看这U体pLw是否支持非寚w讉K ?相关文章:转自http://blog.csdn.net/goodluckyxl/archive/2005/10/17/506827.aspx ARM下的寚w处理 3.13 type qulifiers 有部分摘自ARM~译器文档对齐部?/p>
寚w的? p = (char*)&a; /* 发现自己的审观不咋的,得漂亮的人家觉得不漂亮。还是照着大家要求的画一个?/span> 主要解决的问题是Q这ơ行列都用宏表示Q这样可以修改行列,H口大小也动态改变?/span> 另外长条旋{变成Z型问题也解决Q主要是取模的时候绕回去了?/span> 其中最重要的要是解决了刷新闪烁问题,管HAM2008指点q,始终没做成,q次vczh说了一句话q醒了我。根本不应该使用InvalidateRect函数Q直接画Q然后用~冲DC可以了?br> 如此讄各个宏后可以用了 如果?/span>GTK环境则需要另外设|两个变量,一个是分配调色板,一个是指明长度。若?/span>win32环境无需q两个变量了。该条g~译用于生成不同q_下的产品。即~译代码的不同部分,q就是预处理的一个功能?/span> ?Typedef的?br> ?关于颜色的管理的几个c?/strong> ColourDesired 颜色使用一个长整ŞQ也是?/span>32位来描述一U颜艌Ӏ?/span> 主要看两?/span>Set函数的实玎ͼW一个是从指定的三基色的值来构造一U颜艌Ӏ?br> 从代码看Z高到低依ơ是bgrQ这个顺序正好是RGB模型。那么每个值占8位。d?/span>24位,最高的8位我xalpha通道吧?/span> 另一U是从一个数l构造,目前猜测?/span>xpm格式描述的数l的部分。他首先有个提取十六q制真值的函数作ؓ辅助Q比较简单?/span> 再看一个图标的数组 可以看到该字W图像由三种W号l成Q然后三U符L颜色昄是这么描q的" c None", ". c #000000", "+ c #808080", Set函数遇到一?/span>#号就开始提取计颜?/span>rgbg。那么整个图像应该是通过q个Set函数的几ơ调用进行的?/span>ColourAllocatedcȝ单的把上一个类求的Dl他的成员。具体作用还不清楚?/span>ColourPaircd含以上两个类的对象,q些可能是设计上的原因。因为具体的操作都是ColourDesired完成?/span>?字节寚w对程序的影响:
讄构体如下定义Q?br>struct A
{
int a;
char b;
short c;
};
struct B
{
char b;
int a;
short c;
};
现在已知32位机器上各种数据cd的长度如?
char:1(有符hW号?
short:2(有符hW号?
int:4(有符hW号?
long:4(有符hW号?
float:4 double:8
那么上面两个l构大小如何?
l果?
sizeof(strcut A)gؓ8
sizeof(struct B)的值却?2
#pragma pack (2) /*指定?字节寚w*/
struct C
{
char b;
int a;
short c;
};
#pragma pack () /*取消指定寚wQ恢复缺省对?/
sizeof(struct C)值是8?br>修改寚wgؓ1Q?br>#pragma pack (1) /*指定?字节寚w*/
struct D
{
char b;
int a;
short c;
};
#pragma pack () /*取消指定寚wQ恢复缺省对?/
sizeof(struct D)gؓ7?br>后面我们再讲?pragma pack()的作??~译器是按照什么样的原则进行对齐的?
对于char型数据,其自w对齐gؓ1Q对于short型ؓ2Q对于int,float,doublecdQ其自n寚wgؓ4Q单位字节?br>2.l构体或者类的自w对齐|其成员中自n寚w值最大的那个倹{?br>3.指定寚w?/font>Q?pragma pack (value)时的指定寚w值value?br>4.数据成员、结构体和类的有效对齐|自n寚w值和指定寚wg的那个倹{?br>?了这些|我们可以很方便的来讨论具体数据l构的成员和其自w的寚w方式。有效对齐值N是最l用来决定数据存攑֜址方式的|最重要。有效对齐NQ就?表示“寚w在N?#8221;Q也是说该数据?存放起始地址%N=0".而数据结构中的数据变量都是按定义的先后顺序来排放的。第一个数据变量的起始地址是?据结构的起始地址。结构体的成员变量要寚w排放Q结构体本n也要Ҏ自n的有效对齐值圆?是l构体成员变量占用总长度需要是对结构体有效寚w值的整数 倍,l合下面例子理解)。这样就不能理解上面的几个例子的g?br>例子分析Q?br>分析例子BQ?br>struct B
{
char b;
int a;
short c;
};
?设B从地址I间0x0000开始排放。该例子中没有定义指定对齐|在笔者环境下Q该值默认ؓ4。第一个成员变量b的自w对齐值是1Q比指定或者默认指?寚w?,所以其有效寚wgؓ1Q所以其存放地址0x0000W合0x0000%1=0.W二个成员变量aQ其自n寚wgؓ4Q所以有效对齐g?Q?所以只能存攑֜起始地址?x0004?x0007q四个连l的字节I间中,复核0x0004%4=0,且紧靠第一个变量。第三个变量c,自n寚wgؓ 2Q所以有效对齐g?Q可以存攑֜0x0008?x0009q两个字节空间中Q符?x0008%2=0。所以从0x0000?x0009存放?都是B内容。再看数据结构B的自w对齐gؓ其变量中最大对齐?q里是bQ所以就?Q所以结构体的有效对齐g?。根据结构体圆整的要求, 0x0009?x0000=10字节Q(10Q?Q%4Q?。所?x0000A?x000B也ؓl构体B所占用。故B?x0000?x000B 共有12个字?sizeof(struct B)=12;其实如果p一个就来说它已满_节对齐了, 因ؓ它的起始地址?,因此肯定是对齐的,之所以在后面补充2个字?是因为编译器Z实现l构数组的存取效?试想如果我们定义了一个结构B的数l??么第一个结构v始地址?没有问题,但是W二个结构呢?按照数组的定?数组中所有元素都是紧挨着?如果我们不把l构的大补充ؓ4的整数?那么下一 个结构的起始地址是0x0000A,q显然不能满结构的地址寚w?因此我们要把l构补充成有效对齐大的整数?其实诸如:对于char型数据,?自n寚wgؓ1Q对于short型ؓ2Q对于int,float,doublecdQ其自n寚wgؓ4Q这些已有类型的自n寚wg是基于数l考虑??是因些类型的长度已知?所以他们的自n寚wg已知了.
同理,分析上面例子CQ?br>#pragma pack (2) /*指定?字节寚w*/
struct C
{
char b;
int a;
short c;
};
#pragma pack () /*取消指定寚wQ恢复缺省对?/
W?一个变量b的自w对齐gؓ1Q指定对齐gؓ2Q所以,其有效对齐gؓ1Q假设C?x0000开始,那么b存放?x0000Q符?x0000%1= 0;W二个变量,自n寚wgؓ4Q指定对齐gؓ2Q所以有效对齐gؓ2Q所以顺序存攑֜0x0002?x0003?x0004?x0005四个q箋 字节中,W合0x0002%2=0。第三个变量c的自w对齐gؓ2Q所以有效对齐gؓ2Q顺序存?br>?x0006?x0007中,W合 0x0006%2=0。所以从0x0000?x00007共八字节存放的是C的变量。又C的自w对齐gؓ4Q所以C的有效对齐gؓ2。又8%2=0,C 只占?x0000?x0007的八个字节。所以sizeof(struct C)=8.?如何修改~译器的默认寚w?
?针对字节寚w,我们在编E中如何考虑?
如果在编E的时候要考虑节约I间的话,那么我们只需要假定结构的首地址?,然后各个变量按照上面的原则进行排列即?基本的原则就是把l构中的变量按照 cd大小从小到大声明,量减少中间的填补空?q有一U就是ؓ了以I间换取旉的效?我们昄的进行填补空间进行对?比如:有一U用空间换旉?法是昑ּ的插入reserved成员Q?br> struct A{
char a;
char reserved[3];//使用I间换时?br> int b;
}
reserved成员Ҏ们的E序没有什么意?它只是v到填补空间以辑ֈ字节寚w的目?当然即不加q个成员通常~译器也会给我们自动填补寚w,我们自己加上它只是v到显式的提醒作用.?字节寚w可能带来的隐?
unsigned int i = 0x12345678;
unsigned char *p=NULL;
unsigned short *p1=NULL;
*p=0x00;
p1=(unsigned short *)(p+1);
*p1=0x0000;
最后两句代码,从奇数边界去讉Kunsignedshort型变量,昄不符合对齐的规定?br>在x86上,cM的操作只会媄响效率,但是在MIPS或者sparc上,可能是一个error,因ؓ它们要求必须字节寚w.?如何查找与字节对齐方面的问题:
3. 如果支持看设|了寚w与否,如果没有则看讉K旉要加某些Ҏ的修饰来标志其特D访问操作?/p>
from DUI0067D_ADS1_2_CompLib
1.__align(num)
q个用于修改最高别对象的字节边界。在汇编中用LDRD或者STRD?br> p用到此命令__align(8)q行修饰限制。来保证数据对象是相应对齐?br> q个修饰对象的命令最大是8个字节限?可以?字节的对象进?字节
寚w,但是不能?字节的对?字节寚w?br> __align是存储类修改,他只修饰最高cd对象不能用于l构或者函数对象?br>
2.__packed
__packed是进行一字节寚w
1.不能对packed的对象进行对?br> 2.所有对象的d讉K都进行非寚w讉K
3.float及包含float的结构联合及未用__packed的对象将不能字节寚w
4.__packed对局部整形变量无影响
5.强制由unpacked对象向packed对象转化是未定义,整Ş指针可以合法?br> 义ؓpacked?br> __packed int* p; //__packed int 则没有意?br> 6.寚w或非寚wd讉K带来问题
__packed struct STRUCT_TEST
{
char a;
int b;
char c;
} ; //定义如下l构此时b的v始地址一定是不对齐的
//在栈中访问b可能有问?因ؓ栈上数据肯定是对齐访问[from CL]
//下面变量定义成全局静态不在栈?
static char* p;
static struct STRUCT_TEST a;
void Main()
{
__packed int* q; //此时定义成__packed来修饰当前q指向为非寚w的数据地址下面的访问则可以
q = (int*)(p+1);
*q = 0x87654321;
/*
得到赋值的汇编指o很清?br>ldr r5,0x20001590 ; = #0x12345678
[0xe1a00005] mov r0,r5
[0xeb0000b0] bl __rt_uwrite4 //在此处调用一个写4byte的操作函?
[0xe5c10000] strb r0,[r1,#0] //函数q行4ơstrb操作然后q回保证了数据正的讉K
[0xe1a02420] mov r2,r0,lsr #8
[0xe5c12001] strb r2,[r1,#1]
[0xe1a02820] mov r2,r0,lsr #16
[0xe5c12002] strb r2,[r1,#2]
[0xe1a02c20] mov r2,r0,lsr #24
[0xe5c12003] strb r2,[r1,#3]
[0xe1a0f00e] mov pc,r14
*/
如果q没有加__packed修饰则汇~出来指令是q样直接会导致奇地址处访问失?br>[0xe59f2018] ldr r2,0x20001594 ; = #0x87654321
[0xe5812000] str r2,[r1,#0]
*/
}
VOID OnPaint()
{
HDC hdc = GetDC(hWnd);
HDC bitmap_dc = CreateCompatibleDC(hdc);
HBITMAP bitmap = CreateCompatibleBitmap(hdc,1024,768);
SelectObject(bitmap_dc,bitmap);
/**//********************************************
DrawBlock
*********************************************/
int x = tetris.GetX();
int y = tetris.GetY();
for(int i=0; i<4; ++i)
{
for(int j=0; j<4; ++j)
{
if(current_block[i][j] == 1)
{
DrawBlock(bitmap_dc,y+i+1,x+j+1,3,3,tetris.GetColor(),RGB(0,0,0));
}
}
}
/**//*****************************************
*DrawContainer
******************************************/
for(int i=0; i<ROWS; ++i)
{
for(int j=0; j<COLS; ++j)
{
if(Container[i][j] == 1)
{
DrawBlock(bitmap_dc,i+1,j+1,3,3,ColorTable[i][j],RGB(0,0,0));
}
}
}
BitBlt(hdc,0,0,1024,768,bitmap_dc,0,0,SRCCOPY);
DeleteDC(bitmap_dc);
DeleteObject(bitmap);
ReleaseDC(hWnd,hdc);
}
以上是GDI~冲的主要实C码?br>
可执行文件下?/a>
代码q是{全部完善后上传吧。Redist误行下载?/span>
代码估计要有大的改动Q感觉现在的代码没一点C++的味道?br>有点单,用陈坤的话说是扩展性不好?
#include<iostream>
#include<vector>
using namespace std;
void Print(vector<int>& vec)
{
for(int i = 0; i < vec.size(); ++i)cout<<' '<<vec[i];
cout<<endl;
}
int main()
{
vector<int> first;
vector<int> second(4, 1000);
vector<int> third(second.begin() + 2, second.end());
vector<int> forth(third);
vector<int>::iterator it;
int val[] =
{1,2,3,4};
vector<int> fifth(val, val + sizeof(val) / sizeof(val[0]));
cout<<"First:";
Print(first);
cout<<"Second:";
Print(second);
cout<<"Third:";
Print(third);
cout<<"Forth:";
Print(forth);
cout<<"Fifth:";
Print(fifth);
first.swap(fifth);
cout<<"First:";
Print(first);
first.push_back(12);
cout<<"First:";
Print(first);
it = first.begin() + 2;
first.erase(it,first.end());
cout<<"First:";
Print(first);
it = first.begin();
first.insert(it,100);
cout<<"First:";
Print(first);
system("pause");
return 0;
}
Deque操作代码cM?br>优势Q比之Vector在头部插入删除元素也有很高效率。也支持q代器随问。不q元素在内存中不q箋?br>
List操作基本相同不过多了一些功?br>优势Q高效遍历元素,帔R旉插入删除L位置元素?br>
#include<iostream>
#include<list>
using namespace std;
void Print(list<int>& ls)
{
list<int>::iterator it = ls.begin();
for(; it != ls.end(); ++it)cout<<' '<<*it;
cout<<endl;
}
void Print(list<double>& ls)
{
list<double>::iterator it = ls.begin();
for(; it != ls.end(); ++it)cout<<' '<<*it;
cout<<endl;
}
int main()
{
list<int> first;
list<int> second(4, 1000);
list<int>::iterator it;
double first_val[] =
{1.0,3.0,2.0,4.0};
list<double> third(first_val, first_val + sizeof(first_val) / sizeof(first_val[0]));
double sencond_val[] =
{1.1,4.3,1.4,2.9};
list<double> fourth(sencond_val, sencond_val + sizeof(sencond_val)/sizeof(sencond_val[0]));
it = first.begin();
first.insert(it,100);
cout<<"First:";
Print(first);
it = first.begin();
first.splice(it,second);//splice四个参数Q第一个参数是插入的位|,W二个是插入源,W三四个参数指定范围
cout<<"First:";
Print(first);
first.remove(100);
cout<<"First:";
Print(first);
third.sort();
fourth.sort();
cout<<"Third:";
Print(third);
cout<<"Fourth:";
Print(fourth);
third.merge(fourth);
cout<<"Third:";
Print(third);
system("pause");
return 0;
}
splice在代码中已经说明Qmerge函数合ƈ两个list而且是按照从到大的序Qmerge有另一个版本包含两个参敎ͼ另一个是一?br>q回boolcd的函敎ͼ说明了比较规则。用法相同。另外一些函C用比较简单?br>该类W记均参考:www.cplusplus.com
2)C 语言是所谓的“内?#8221;语言Q就其语a本n来说很小Q不多的关键字,E序程控制Q数据类型等Q;所以,C 语言内核开发出来之后,Dennis Ritchie ? Brian Kernighan q C 本n重写? 90% 以上? UNIX pȝ函数Qƈ且把其中最常用的部分独立出来,形成头文件和对应? LIBRARYQC run-time library 是q样形成的?
3)随后Q随着 C 语言的流行,各个 C ~译器的生?个体/团体都遵循老的传统Q在不同q_上都有相对应? Standard LibraryQ但大部分实现都是与各个q_有关的。由于各? C ~译器对 C 的支持和理解有很多分歧和微妙的差别,所以就有了 ANSI CQANSI C Q主观意图上Q详l的规定? C 语言各个要素的具体含义和~译器实现要求,引进了新的函数声明方式,同时订立? Standard Library 的标准Ş式。所以Cq行时库q译器生商提供。至于由其他厂商/个h/团体提供的头文g和库函数Q应当称为第三方 C q行库(Third party C run-time librariesQ?
4)C run-time library里面含有初始化代码,q有错误处理代码(例如divide by zero处理)。你写的E序可以没有math库,E序照样q行Q只是不能处理复杂的数学q算Q不q如果没有了C run-time库,main()׃会被调用Qexit()也不能被响应。因为C run-time library包含了CE序q行的最基本和最常用的函数?
5)C C++ 世界里,有另外一个概?Standard C++ Library,它包括了上面所说的 C run-time library ? STL。包? C run-time library 的原因很明显QC++ ? C 的超集,没有理由再重新来一? C++ run-time library. VC针对C++ 加入的Standard C++ Library主要包括QLIBCP.LIB, LIBCPMT.LIB? MSVCPRT.LIB
6)Windows环境下,VC提供? C run-time library又分为动态运行时库和静态运行时库?
动态运行时库主要是DLL库文件msvcrt.dll(or MSVCRTD.DLL for debug build),对应的Import library文g是MSVCRT.LIB(MSVCRTD.LIB for debug build)
静态运行时?release?对应的主要文件是Q?
LIBC.LIB (Single thread static library, retail version)
LIBCMT.LIB (Multithread static library, retail version)
msvcrt.dll提供几千个C函数Q即使是像printfq么低的函数都在msvcrt.dll里。其实你的程序运行时Q很大一部分旉时在q些q行库里q行。在你的E序(release?被编译时QVC会根据你的编译选项(单线E、多U程或DLL)自动相应的q行时库文g(libc.lib,libcmt.lib或Import library msvcrt.lib)链接q来?
~译时到底哪个C run-time library联入你的E序取决于编译选项Q?
/MD, /ML, /MT, /LD (Use Run-Time Library)
你可以VC中通过以下Ҏ讄选择哪个C run-time library联入你的E序Q?
To find these options in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Code Generation in the Category box. See the Use Run-Time Library drop-down box.
从程序可UL性考虑,如果两函数都可完成一U功能,选运行时库函数好,因ؓ各个 C ~译器的生商对标准C Run-time library提供了统一的支?
1//每种环境都设|一个宏且都|?
2#define PLAT_GTK 0
3#define PLAT_GTK_WIN32 0
4#define PLAT_MACOSX 0
5#define PLAT_WIN 0
6#define PLAT_WX 0
7#define PLAT_FOX 0
8//如果该环境有效则取消原有宏且|?
9#if defined(FOX)
10#undef PLAT_FOX
11#define PLAT_FOX 1
12
13#if defined(__WIN32__) || defined(_MSC_VER)
14#undef PLAT_GTK_WIN32
15#define PLAT_GTK_WIN32 1
16#endif
17
18#else
19#undef PLAT_WIN
20#define PLAT_WIN 1
21
22#endif
23class Palette
{
int used;
int size;
ColourPair *entries;
#if PLAT_GTK//1为真Q这里可以是一个常量表辑ּ
void *allocatedPalette; // GdkColor *
int allocatedLen;
#endif
typedef void *FontID;
typedef void *SurfaceID;
typedef void *WindowID;
typedef void *MenuID;
typedef void *TickerID;
typedef void *Function;
typedef void *IdlerID;
不同q_的具体类型不同,可以用该Ҏ定义新的名字QɽE序更清晰?br>
void Set(unsigned int red, unsigned int green, unsigned int blue)
{
co = red | (green << 8) | (blue << 16);
}
static inline unsigned int ValueOfHex(const char ch)
{
if (ch >= '0' && ch <= '9')
return ch - '0';
else if (ch >= 'A' && ch <= 'F')
return ch - 'A' + 10;
else if (ch >= 'a' && ch <= 'f')
return ch - 'a' + 10;
else
return 0;
}
void Set(const char *val)
{
if (*val == '#')
{
val++;
}
unsigned int r = ValueOfHex(val[0]) * 16 + ValueOfHex(val[1]);
unsigned int g = ValueOfHex(val[2]) * 16 + ValueOfHex(val[3]);
unsigned int b = ValueOfHex(val[4]) * 16 + ValueOfHex(val[5]);
Set(r, g, b);
}
1/**//* XPM */
2static char * arrow_xpm[] =
{
3"12 12 3 1",
4" c None",
5". c #000000",
6"+ c #808080",
7" ",
8" .+ ",
9" .+ ",
10" +.+ ",
11"
..+ ",
12"
+ ",
13"
+ ",
14"
..+ ",
15" +.+ ",
16" .+ ",
17" .+ ",
18" "};
19
const_castQ?/span>reinterpret_castQ?/span>static_castQ?/span>dynamic_cast{等?nbsp;
1Q?/span>static_cast<T*>(a)
地址a转换成类型TQT和a必须是指针、引用、算术类型或枚Dcd?nbsp;
表达?/span>static_cast<T*>(a), a的D{换ؓ模板中指定的cdT。在q行时{换过E中Q不q行cd查来保转换的安全性?nbsp;
例子Q?nbsp;
2Q?/span>dynamic_cast<T*>(a)
完成cdơ结构中的提升。T必须是一个指针、引用或无类型的指针。a必须是决定一个指针或引用的表辑ּ?nbsp;
表达?/span>dynamic_cast<T*>(a) aD{换ؓcd为T的对象指针。如果类型T不是a的某个基cdQ该操作返回一个空指针?nbsp;
例子Q?nbsp;
3Q?/span>const_cast<T*>(a)
Lcd中的帔RQ除?/span>const或不E_的变址敎ͼT和a必须是相同的cd?nbsp;
表达?/span>const_cast<T*>(a)被用于从一个类中去除以下这些属性:const, volatile, ?nbsp;__unaligned?nbsp;
例子Q?
4Q?/span>reinterpret_cast<T*>(a)
M指针都可以{换成其它cd的指针,T必须是一个指针、引用、算术类型、指向函数的指针或指向一个类成员的指针?nbsp;
表达?/span>reinterpret_cast<T*>(a)能够用于诸如char* ?nbsp;int*Q或者One_class* ?nbsp;Unrelated_class*{类DL转换Q因此可能是不安全的?nbsp;
例子Q?nbsp;
本文转自http://www.libing.net.cn/read.php?520
Ҏ出错的常用用法,做了一些整理?br>
一Q?/span>起别名的两种用法
比如pInt a,b;
W一U表C: int*a;int*b;
W二U表C: int*a,b;
所以第一U更像一个类型,W二U更像宏?/span>
二.旧式代码中声明对?/span>
三.代码?/span>
为复杂的声明定义一个新的简单的别名
ҎQ?/span>在原来的声明里逐步用别名替换一部分复杂声明Q如此@环,把带变量名的部分留到最后替换,得到的就是原声明的最化版
q个声明引入?/span> PF cd作ؓ函数指针的同义字Q该函数有两?/span> const char * cd的参C及一?/span> int cd的返回倹{?/span>
如果要用下列Ş式的函数声明Q那么上q这?/span> typedef 是不可或~的Q?/p>
PF Register(PF pf);
Register() 的参数是一?/span> PF cd的回调函?/span>Q返回某个函数的地址Q其|名与先前注册的名字相同。如果不?/span> typedefQ那么代码是q样的: