tips

这一章将不定时的增加小tips或者小总结,内容不定

tips1:strlen strcpy sizeof 小结

//C语言函数有的就是控制要精细,当然没有包括sizeof运算符
strlen  计算字符串到'\0'不包含'\0'的字符长度
strcpy 复制字符串到'\0'包含'\0'的字符
sizeof  求的是内存字节数,是一个对象所占的内存,只要看清楚对象是什么东东,就可方便得出内存字节数
eg:
char cArray[]="abc\0def";
cout<<strlen(cArray)<<endl;//output 3, interupt when occur '\0'
cout<<sizeof cArray<<endl;//output 8
char destArray[10]={0};
strcpy(destArray,cArray);
cout<<destArray<<endl;//output abc

eg://all is sizeof test
char *pChar;//4 对象是指针
char *pChar=new char[100];//4 对象是指针
typedef struct Test{//8 内存对齐后以大的int再把char补齐3字节为int
    int a;
    char ch;
};
char cArray[]="hello";//6 cArray是一个数组,求数组所占内存,因为这是一个字符数组所以还有一个'\0',C中的字符数组太特别了
与char *ch="hello";不同。。ch这里是一个指针
int iArray[5];//20=4*5

tips2:sizeof的实现

#define my_sizeof(L_Value) ((char*)(&L_Value+1)-(char*)&L_Value)

tips3:#define中的 #与##

//#define GPEBLT_FUNCNAME(basename) (SCODE (GPE::*)(struct GPEBltParms *))&GPE::##basename
//在#define中,标准只定义了#和##两种操作。#用来把参数转换成字符串,##则用来连接两个前后两个参数,把它们变成一个字符串。 
//直接上例子
#include <stdio.h>
#define paster(n) printf("token " #n" = %d\n ",token##n) 
int main()
{
	int token9 = 10;
	paster(9);
	return 0;
}
Output:
token 9 = 10

tips4:关于空的class的size问题//不知道原出处了。。

class A{};
class B:public virtual A{};
class C:public virtual A{};
class D:public B,public C{};

//以下结果和编译器相关,对于部分编译器,可能会出现下面的结果
sizeof A; //结果为1
sizeof B; //结果为8
sizeof C; //结果为8
sizeof D; //结果为12

这些没有任何成员的类,大小居然都不是0。
首先,对于第一个sizeof A,被编译器安插了一个char,为的是使这个类的两个对象能够在内存中被分配独一无二的地址。

B和C是由于某些C++编译器本身机制,也被安插了一个char,再有Alignment的限制,填补了3个字节;加上其中的指向virtual base class subobject的指针,一共是8个字节。

对于D,除了安插的char外,还有两个指向virtual base class subobject的指针,共12字节。

 但这个结果是和编译器相关的,对于VC, 由于B、C、D的大小不在是0,也不需要安插char,所以会有以下结果:
sizeof A; //结果为1
sizeof B; //结果为4
sizeof C; //结果为4
sizeof D; //结果为8

tips5:判断小端系统//来源于cocos2d-x源码中

#define CC_HOST_IS_BIG_ENDIAN (bool)(*(unsigned short *)"\0\xff" < 0x100)
//0xff   →255
//0x100→256
小端系统下,地址高高低低完全对应

tips6:xutility中的advance和distance

#include <xutility>
advance(it,2);//等于迭代器it += 2;
ptrdiff_t dt = distance(it1,it2);//等于迭代器it2-迭代器it1
用来移动stl中的迭代器再适合不过了

tips7:offsetof

作用:
表示一个成员在struct或union中的偏移量,#include <cstddef>
实现代码:
#define offsetof(s, m)   (size_t)&(((s *)0)->m)  
实现详解:
s是一个结构名,它有一个名为m的成员(s和m 是宏offsetof的形参),它实际是返回结构s的成员m的偏移地址。
(s *)0 是骗编译器说有一个指向类(或结构)s的指针,其地址值0 。
&((s *)0)->m   是要取得类s中成员变量m的地址。 因基址为0,这时m的地址当然就是m在s中的偏移。
最后转换size_t 型,即unsigned int。

tips8:记录一个c语言的小东东setjmp longjmp

作用:异常处理
/*
 * int setjmp(jmp_buf envbuf);
 * setjmp函数用缓冲区envbuf保存系统堆栈的内容,以便后续的longjmp函数使用。setjmp函数初次启用时返回0值。
 * void longjmp(jmp_buf envbuf, int val);
 * longjmp函数中的参数envbuf是由setjmp函数所保存的堆栈环境,参数val设置setjmp函数的返回值。
 * longjmp函数本身是没有返回值的,它执行后跳转到保存envbuf参数的setjmp函数调用,并由setjmp函数调用返回,此时setjmp函数的返回值就是val。
 * 通俗的解释是:
 * 先调用setjmp,用变量envbuf记录当前的位置,然后调用longjmp,返回envbuf所记录的位置,并使setjmp的返回值为val。当时用longjmp时,envbuf的内容被销毁了。
 * 其实这里的“位置”一词真正的含义是栈定指针。
 *
*/
eg:
//code from: C专家编程 
#include <setjmp.h>
#include <stdio.h>
void banana();
jmp_buf buf;

void banana()
{ 
	printf("in banana() \n"); 
	longjmp(buf,1);
	printf("you'll never see this,because i longjmp'd");
}

int main()
{ 
	if(setjmp(buf))
		printf("back in main\n"); 
	else//首次调用返回0
	{ 
		printf("first time through\n"); 
		banana(); 
	}
}
Output:
first time through
in banana()
back in main

/*
 * int setjmp(jmp_buf jmpb)设置缓冲区来保存堆栈的内容,将保存的上下文存入进程的自身的数据空间(u区),
 * 并继续在当前的上下文中执行,一旦碰到了longjmp,进程就从该进程的u区,取出先前保存的上下文,并恢复该进程的上下文为先前保存的上下文。
 * 这时核心将使得进程从setjmp处执行(摘自:unix平台下c语言高级编程 指南)
 * void longjmp(jmp_buf jmpb, int retval) 使进程返回到setjmp处执行,retval 表示此时setjmp的返回值。
 * longjmp必须在setjmp调用之后,而且longjmp必须在setjmp的作用域之内。
*/
jmp_buf mark;

void Func1()
{
	// 其它代码的执行
	// 判断程序远行中,是否出现错误,如果有错误,则跳转!
	if(1) longjmp(mark, 1);//因为1为真,跳到case 1 break; 就执行exit(0)了
}
void Func2()
{
	// 其它代码的执行
	// 判断程序远行中,是否出现错误,如果有错误,则跳转!
	if(2) longjmp(mark, 2);
}
void Func3()
{
	// 其它代码的执行
	// 判断程序远行中,是否出现错误,如果有错误,则跳转!
	if(-1) longjmp(mark, -1);
}
void main( void )
{
	int jmpret;
	jmpret = setjmp( mark );
	if( jmpret == 0 )
	{
		// 其它代码的执行
		// 下面的这些函数执行过程中,有可能出现异常
		Func1();
		Func2();
		Func3();
		// 其它代码的执行
	}
	else
	{
		// 错误处理模块
		switch (jmpret)
		{
		case 1:
			printf( "Error 1\n");
			break;
		case 2:
			printf( "Error 2\n");
			break;
		case 3:
			printf( "Error 3\n");
			break;
		default :
			printf( "Unknown Error");
			break;
		}
		exit(0);
	}
	return 0;
}

tips9:enum小结

如果全部枚举符的值均为非负,该枚举的表示范围就是[0:2^k-1],2^k是能使所有枚举符位于此范围内的最小的2的幂;

eg:
enum open_modes 
{
	input = 1, 
	output, 
	append
};
//范围 [0,2^2-1]
如果存在负的枚举符值,则该枚举的取值范围就是[-2^k:2^k-1],这样就定义了一个最小的位段,其中能保存所有的枚举符值的常规2补码表示.
eg:
enum e3 {min = -10, max = 1000}; //范围-1024:1023
enum参与运算
eg:
#include <iostream>
#include <cstddef>
using std::cout;
using std::endl;
using std::size_t;

typedef enum
{
	fileOpen,
	fileClose,
	fileAttach
};

int main()
{
	for(size_t i = fileOpen; i <= fileAttach; ++i)
	{
		cout<<i<<'\t';
	}
	cout<<endl;
	return 0;
}

tips10:c time库用法小记

#include <ctime>
1.执行程序时间差
time_t start,end;
time(&start);
cout<<"hello"<<endl;
Sleep(1000);
time(&end);
cout<<difftime(end,start)<<endl;
2.转换服务器时间
long long int timeSec = 1353735416;//假如这是服务器的时间
char str[64] = {0};
time_t timep = timeSec;
//
//sprintf(str, "%s",asctime(gmtime(&timep)));
//str是 星期+日期+时间
// 
//如果希望自己定义格式,用下面的办法也可以。
tm *timeStuct = gmtime(&timep);
sprintf(str, "%02d/%02d/%02d %02d:%02d",
timeStuct->tm_year + 1900,
timeStuct->tm_mon + 1,
timeStuct->tm_mday,
timeStuct->tm_hour,
timeStuct->tm_min);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值