1,预定义宏
__LINE__ 当前代码行的行号(等于读到目前为止新行的字符数)
__FILE__ 源文件的名字
__DATE__ 以"Mmm dd yyyy"的形式转换日期
__TIME__ 以"hh:mm:ss"的形式转换日期
__cplusplus 一个包含正式的C++标准的日期
2,如果代码是在C/C++混合编程环境中编写的,可以将新的C++代码与旧的C代码相链接。所需要做的所有事情就是通过extern "C"链接规范来告诉C++翻译器,不要“砍掉”与C组件相匹配的外部名字,例如:
extern "C" void f(); // f() 在C环境下被编译
C++标准库中的C部分知道是否该砍掉名字(在第一章已解释过),这取决于在什么模式下(C或C++)编译。如果仔细阅读标准C头文件会发现销售商使用__cplusplus宏通过一个extern "C"块根据以下模式条件隐藏了标准C声明:
#if defined(__cplusplus)
extern "C"
{
#endif
<C声明放在此处>
#if defined(__cplusplus)
}
#endif
3,#if defined(X) <==> #ifdef X
defined运算符比其右边的等价指令要灵活多,因为可以把许多测试联合起来构成一个表达式:
#if defined(__cplusplus) && !defined(DEBUG)
4,预处理运算符
# 字符串化
## 加标记
defined 符号表查询
#define trace(x,format) printf(#x "=%" #format "\n",x)
#define trace2(i) trace(x##i,d)
5,当宏必须作出选择时,好的做法是把它写成一个表达式而不是语句
void __assert(char *cond,char *fname,long lineno){
fprintf(stderr,"Assertiion failed:%s, file %s, line %ld\n",cond,fname,lineno);
abort();
}
#define assert(cond) \
if(!(cond)) __assert(#cond,__FILE__,__LINE__) // 不好
#define assert(cond) \
((cond)?(void)0:__assert(#cond,__FILE__,__LINE__) // 好
6,预处理器的宏替换功能显而易见为你提供了很大的灵活性。但要记住以下两点限制:
A,无论何时预处理器在其替代文本中遇到当前的宏,不管在进程中有多么深的嵌套,它都不做扩展,只是保持不变(否则进程将永远不终止!)。
B,如果被充分扩展的语句相似于一条预处理指令(例如扩展以后结果是一条#include指令),它没有被调用,而是逐字地留在程序文本中。
7,三字符运算符序列
??= #
??( [
??/ \
??) ]
??' ^
??< {
??! |
??> }
??- ~
8,新的C++双字符运算符和保留字
<% {
%> }
<: [
:> ]
%% #
Bitand &
And &&
Bitor |
Or ||
Xor ^
Compl ~
and_eq &=
or_eq |=
xor_eq ^=
Not !
not_eq !=
9,翻译阶段
标准C和C++定义了9个不同的翻译阶段。当然,实现没有必要在代码中分成9个独立的阶段,但是翻译的结果必须好像已经这样做了一样,这9个阶段是:
1,物理源字符被映射到源字符集中。其中包括三字符组合替换以及诸如把回车/换行映射到一个单独的MSDOS环境下的换行字符那样的东西。在C++程序中,任何不在基础源字符集中的字符都被它的通用字符名替换。
2,所有以反斜杠结束的行都和它们接下来的行合并,并且删去反斜杠。
3,源码被分析成预处理标记,并且注释被一个单独的空字符所替换,C++双字符被识别为标记。
4,调用预处理指令并且扩展宏,对于任何被包含的文件循环地重复步骤1到4。
5,源字符退出字符常量序列,普通字符名被映射成执行字符集成员(例如,'\a'将在ASCII环境下转换成7的一个字节值)。
6,相邻的字符串被连接。
7,传统的编译:词汇和语义分析,并翻译成汇编语言或机器码。
8,(只有C++)执行任何待解决的模板实例。
9,链接:解决外部引用,准备好程序映像以便执行。
预处理器由步骤1到4组成。
10,存储两个指针差的便捷方法是把这个差存储在ptrdiff_t中,它在stddef.h中定义,包含在<iostream>中。
ptrdiff_t diff=p-q;
11,说明指针转换
#include<iostream>
using namespace std;
void main(){
int i=7;
char *cp=(char *)&i;
cout<<"The integer at "<<&i<<" == "<<i<<endl;
//分别打印每个字节的值
for(int n=0;n<sizeof i;n++)
cout<<"The byte at "<<(void *)(cp+n)<<" == "<<int(*(cp+n))<<endl;
}
12,位域
#include<iostream>
using namespace std;
struct Date{
unsigned day:5;
unsigned mon:4;
unsigned year:7;
};
void main(){
struct Date d;
d.day=2;
d.mon=8;
d.year=92;
cout<<hex<<*((short *)(&d))<<endl;
}
/////////////////////////////////////////////
#include<iostream>
using namespace std;
struct Date{
unsigned day:5;
unsigned mon:4;
unsigned year:7;
};
void main(){
unsigned short date,year=92,mon=8,day=2;
Date *dp=(Date *)&date;
dp->day=day;
dp->mon=mon;
dp->year=year;
cout<<hex<<date<<endl;
}
13,在面向对象操作中,指向一个对象的指针称为“句柄”。
14,普通指针
通常编写能接收指向任意类型参数的函数是很方便的。这是很有必要的,例如,用标准的库函数memcpy,能够从一个地址向另一个地址拷贝一块内存。你也可能想调用memcpy来拷贝自己创建的结构:
struct mystruct a,b;
...
memcpy(&a,&b,sizeof(struct mystruct));
为了操作任意类型的指针,memcpy把它头两个参数声明为void型指针。可以不需要强制类型转换将任何类型的指针赋予void*类型。也可以在C而不是C++中将void*赋予其他任何类型的指针。这里说明了void指针的memcpy函数的简洁实现:
void* memcpy(void* target, const void* source, size_t n){
char *targetp=(char *)target;
const char *sourcep=(const char *)source;
while(n--)
*targetp++=*sourcep++;
return target;
}
这个版本的memcpy必须把指向void的指针赋予指向char指针一,这样它就可以每次传递内存块的一个字节,并对这个字节中的数据进行拷贝。试图复引用一个void*是没有意义的,因为它的大小是未知的。
15,
strncpy(s,t,n)[n]='\0';
a[i]=*(a+i)=*(i+a)=i[a]
size_t n=sizeof a/sizeof a[0];
cout<<(void*)"hello"<<endl;
cout<<"hello"[3]<<endl;
p=a+n-1;
for(int i=0;i<n;i++)
cout<<p[-i]<<endl;
16,函数指针
#include<stdio.h>
void main(){
int (*fp)(const char *,...)=printf;
fp("hello\n");
}
17,
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
int comp(const void*, const void*);
void main(int argc, char *argv[]){
qsort(argv+1, argc-1, sizeof argv[0], comp);
while(--argc)
cout<<*++argv<<endl;
}
int comp(const void *p1, const void *p2){
const char *ps1=*(const char **)p1;
const char *ps2=*(char **)p2;
return strcmp(ps1,ps2);
}
18,
#include<stdio.h>
extern void retrieve(void);
extern void insert(void);
extern void update(void);
extern int show_menu(void);
void main(){
int choice;
void (*farray[])(void)={retrieve,insert,update};
for(;;){
choice=show_menu();
if(choice>=1 && choice<=3)
farray[choice-1]();
else if(choice==4)
break;
}
}
19,
#include<iostream>
using namespace std;
class Object{
public:
void retrieve(){
cout<<"Object::retrieve"<<endl;
}
void insert(){
cout<<"Object::insert"<<endl;
}
void update(){
cout<<"Object::update"<<endl;
}
void process(int choice);
private:
typedef void (Object::*Omf)();
static Omf farray[3];
};
Object::Omf Object::farray[3]={&Object::retrieve,&Object::insert,&Object::update};
void Object::process(int choice){
if(0<=choice && choice<=2)
(this->*farray[choice])();
}
void main(){
int show_menu(); // 您所提供的!
Object o;
for(;;){
int choice=show_menu();
if(1<=choice && choice<=3)
o.process(choice-1);
else if(choice==4)
break;
}
}
正文
C与C++代码精粹笔记二2004-12-24 10:44:00
【评论】 【打印】 【字体:大 中 小】 本文链接:http://blog.pfan.cn/book/31.html
阅读(3627) | 评论(0)
版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!
评论