??xml version="1.0" encoding="utf-8" standalone="yes"?> In order to understand why the application does not minimize properly, we need to look into the MFC code that constructs and displays the main window. By placing a breakpoint in the There are two solutions that can be used to solve the flashing problem. The first solution is to make a subclass of the One may ask if the ProcesShellCommand
function, we see that, by default, the AppWnd OnFileNew
handler is called. OnFileNew
calls the CDocument* CDocument* CSingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,BOOL bMakeVisible) OpenDocument
, which creates a new document instance, creates a new frame for the document, and finally displays the window by calling InitialUpdateFrame(pFrame, pDocument, bMakeVisible);
, and displays the view and the mainframe window. The reason why the application does not display correctly when a different SW parameter is chosen instead of SW_SHOW
, is because InitialUpdateFrame
CFrameWnd::ActivateFrame()
calls ShowWindow
during the initialization of the window in the function. This implies that the call to ShowWindow
in InitInstance()
is redundant and not needed.The solution
SingleDocumentTemplate
and call our derived version of OpenDocument
with bMakeVisible = false
for the minimized case. This, however, does not solve the case of using SW_MAXMIMIZE
. Another solution, which is far more simpler and can be used for any ShowWIndow
mode, is to set the application ShowWindow
property prior to initializing the window, as shown below: CSingleDocTemplate * pDocTemplate;
pDocTemplate = new CSingleDocTemplate (
IDR_MAINFRAME,
RUNTIME_CLASS(CMyMFCProgramDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CMyMFCProgramView));
AddDocTemplate(pDocTemplate);
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Add the following line:
// Set the initial window display to whatever mode you like
this->m_nCmdShow = SW_MAXIMIZE;
// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The following line should be deleted since it is not needed
// for a SDI application that used MFC The one and only window has
// been initialized, so show and update it.
//m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
return TRUE;
ShowWindow()
line in the InitInstance
has no purpose, and why Microsoft put that line there in the first place. The answer is, if one decides to construct an SDI application using the MFC application wizard and checks the option not to use MFC, this line is required to show the window. However, Microsoft should have deleted this line if MFC is used. However, since the vast majority of applications initially display ShowWindow
with the SW_SHOW
parameter, calling ShowWindow
twice (the first time in ActivateFrame
, as described above) will not influence the display of the application.
]]>
{
va_list vl;
va_start(vl, pFormatString);<br>
CString strFormat;
strFormat.FormatV(pFormatString, vl); // This Line is important!<br>
// Display message box.
AfxMessageBox(strFormat);
}
void MessageBoxFormatted(HWND hWnd, LPCTSTR pCaption, LPCTSTR pFormatString, ...)
{
va_list vl;
va_start(vl, pFormatString);<br>
TCHAR strFormat[1024]; // Must ensure size!<br>
// Generic version of vsprintf, works for both MBCS and Unicode builds
_vstprintf(strFormat, pFormatString, vl);<br>
// Or use following for more secure code
// _vstprintf_s(strFormat, sizeof(strFormat), pFormatString, vl)<br>
::MessageBox(hWnd, strFormat, pCaption,MB_ICONINFORMATION);
}
]]>
1Q函数指针定?/span>
函数cd Q?/font>*指针变量名)(形参列表)Q?/span>
“函数cd”说明函数的返回类型,׃“()”的优先高于“*”,所以指针变量名外的括号必不可少Q后面的“形参列表”表示指针变量指向的函数所带的参数列表?/span>
例如Q?/span>
int (*f)(int x);
double (*ptr)(double x);
在定义函数指针时h意:
函数指针和它指向的函数的参数个数和类型都应该?/font>?/span>致的Q?/span>
函数指针的类型和函数的返回值类型也必须是一致的?/span>
2Q函数指针的赋?/span>
函数名和数组名一样代表了函数代码的首地址Q因此在赋值时Q直接将函数指针指向函数名就行了?/span>
例如Q?/span>
int func(int x); /* 声明一个函?/font> */
int (*f) (int x); /* 声明一个函数指?/font> */
f=func; /* ?/font>func函数的首地址赋给指针f */
赋值时函数func不带括号Q也不带参数Q由?/font>func代表函数的首地址Q因此经q赋g后,指针f指向函?/font>func(x)的代码的首地址?/span>
3Q通过函数指针调用函数
函数指针是通过函数名及有关参数q行调用的?/span>
与其他指针变量相cMQ如果指针变?/font>pi是指向某整型变量i的指针,?/font>*p{于它所指的变量iQ如?/font>pf是指向某点型变?/font>f的指针,?/font>*pfq价于它所指的变量f。同样地Q?/font>*f是指向函?/font>func(x)的指针,?/font>*f׃表它所指向的函?/font>func。所以在执行?/font>f=func;之后Q?/font>(*f)?/font>func代表同一函数?/span>
׃函数指针指向存储Z的某个函敎ͼ因此可以通过函数指针调用相应的函数。现在我们就讨论如何用函数指针调用函敎ͼ它应执行下面三步Q?/span>
首先Q要说明函数指针变量?/span>
例如Q?/font>int (*f)(int x);
其次Q要对函数指针变量赋倹{?/span>
例如Q?/font> f=func; (func(x)必须先要有定?/font>)
最后,要用 (*指针变量)(参数?/font>);调用函数?/span>
例如Q?/font> (*f)(x);(x必须先赋?/font>)
一?/span> 在字W串前加一?/span>L作用:
?/span> L"我的字符?/span>" 表示?/span>ANSI字符串{换成unicode的字W串Q就是每个字W占用两个字节?/span>
strlen("asd") = 3;
strlen(L"asd") = 6;
二?/span> _T宏可以把一个引号引h的字W串Q根据你的环境设|,使得~译器会Ҏ~译目标环境选择合适的Q?/span>Unicodeq是ANSIQ字W处理方?/span>
如果你定义了UNICODEQ那?/span>_T宏会把字W串前面加一?/span>L。这?/span> _T("ABCD") 相当?/span> L"ABCD" Q这是宽字符丌Ӏ?/span>
如果没有定义Q那?/span>_T宏不会在字符串前面加那个LQ?/span>_T("ABCD") q价于 "ABCD"
三?/span>TEXT,_TEXT ?/span>_T 一L
如下面三语句Q?/span>
TCHAR szStr1[] = TEXT("str1");
char szStr2[] = "str2";
WCHAR szStr3[] = L("str3");
那么W一句话在定义了UNICODE时会解释为第三句话,没有定义时就{于W二句话?/span>
但二句话无论是否定义?/span>UNICODE都是生成一?/span>ANSI字符Ԍ而第三句话L生成UNICODE字符丌Ӏ?/span>
ZE序的可UL性,都用W一U表C方法?/span>
但在某些情况下,某个字符必须?/span>ANSI?/span>UNICODEQ那q后两U方法?/span>
Many C++ Windows programmers get confused over what bizarre identifiers like TCHAR, LPCTSTR are. Here, in brief, I would try to clear out the fog.
In general, a character can be 1 byte or 2 bytes. Lets say 1-byte character is ANSI, using which English characters are represented. And lets say 2-byte character is Unicode, which can represent ALL languages in the world.
VC++ support char and wchar_t as native datatypes for ANSI and Unicode characters respectively.
What if you want your C/C++ program to be Character-mode independent?
That means, instead of replacing:
Collapse | Copy Code
char cResponse; // 'Y' or 'N'
char sUsername[64];
// str* functions
with
Collapse | Copy Code
wchar_t cResponse; // 'Y' or 'N'
wchar_t sUsername[64];
// wcs* functions
You can simply code it:
Collapse | Copy Code
#include<TCHAR.H> // Implicit or explicit include
TCHAR cResponse; // 'Y' or 'N'
TCHAR sUsername[64];
// _tcs* functions
Thus, when your project is being compiled as Unicode, the TCHAR would translate to wchar_t. If it is being compiled as ANSI/MBCS, it would translated to char. Likewise, instead of using strcpy, strlen, strcat (including the secure versions suffixed with _s); or wcscpy, wcslen, wcscat (including secure), you can simply use _tcscpy, _tcslen, _tcscat functions.
When you need to express hard-coded string, you can use:
Collapse | Copy Code
"ANSI String"; // ANSI
L"Unicode String"; // Unicode
_T("Either string, depending on compilation"); // ANSI or Unicode
// or use TEXT macro, if you need more readability.
The non-prefixed string is ANSI string, the L prefixed string is Unicode, and string specified in _T or TEXT would be either, depending on compilation.
String classes, like MFC/ATL's CString implement two version using macro. There are two classes named CStringA for ANSI, CStringW for Unicode. When you use CString (which is a macro/typedef), it translates to either of two classes.
Okay. The TCHAR type-definition was for a single character. You can definitely declare an array of TCHAR.
What if you want to express a character-pointer, or a const-character-pointer - Which one of the following?
Collapse | Copy Code
// ANSI characters
foo_ansi(char*);
foo_ansi(const char*);
/*const*/ char* pString;
// Unicode/wide-string
foo_uni(WCHAR*); // or wchar_t*
foo_uni(const WCHAR*);
/*const*/ WCHAR* pString;
// Independent
foo_char(TCHAR*);
foo_char(const TCHAR*);
/*const*/ TCHAR* pString;
After reading about TCHAR stuff, you'd definitely select the last one as your choice. But here is better alternative. Before that, note that TCHAR.H header file declares only TCHAR datatype and for the following stuff, you need to include Windows.h (defined in WinNT.h).
NOTE: If your project implicitly or explicitly includes Windows.h, you need not to include TCHAR.H
Now, I hope, you understand the following signatures :
Collapse | Copy Code
BOOL SetCurrentDirectory( LPCTSTR lpPathName );
DWORD GetCurrentDirectory(DWORD nBufferLength,LPTSTR lpBuffer);
Continuing. You must have seen some functions/methods asking you to pass number of characters, or returning the number of characters. Well, like GetCurrentDirectory, you need to pass number of characters, and not number of bytes. For example::
Collapse | Copy Code
TCHAR sCurrentDir[255];
// Pass 255 and not 255*2
GetCurrentDirectory(sCurrentDir, 255);
On the other side, if you need to allocate number or characters, you must allocate proper number of bytes. In C++, you can simply use new:
Collapse | Copy Code
LPTSTR pBuffer; // TCHAR*
pBuffer = new TCHAR[128]; // Allocates 128 or 256 BYTES, depending on compilation.
But if you use memory allocation functions like malloc, LocalAlloc, GlobalAlloc etc; you must specify the number of bytes!
Collapse | Copy Code
pBuffer = (TCHAR*) malloc (128 * sizeof(TCHAR) );
Typecasting the return value is required, as you know. The expression in malloc's argument ensures that it allocates desired number of bytes - and makes up room for desired number of characters.
1
本文从介l基概念入手Q探讨了在C/C++中对日期和时间操作所用到的数据结构和函数Qƈ对计时、时间的获取、时间的计算和显C格式等斚wq行了阐q。本文还通过大量的实例向你展CZtime.h头文件中声明的各U函数和数据l构的详l用方法?nbsp;
关键字:UTCQ世界标准时_QCalendar TimeQ日历时_QepochQ时间点Q,clock tickQ时钟计时单元)
1Q概?nbsp;
在C/C++中,对字W串的操作有很多值得注意的问题,同样QC/C++Ҏ间的操作也有许多值得大家注意的地斏V最q,在技术群中有很多|友也多ơ问?qC++语言中对旉的操作、获取和昄{等的问题。下面,在这文章中Q笔者将主要介绍在C/C++中时间和日期的用方?
通过学习许多C/C++库,你可以有很多操作、用时间的Ҏ。但在这之前你需要了解一?#8220;旉”?#8220;日期”的概念,主要有以下几个:
Coordinated Universal TimeQUTCQ:协调世界Ӟ又称Z界标准时_也就是大家所熟知的格林威L准时_Greenwich Mean TimeQGMTQ。比如,中国内地的时间与UTC的时差ؓ+8Q也是UTC+8。美国是UTC-5?nbsp;
Calendar TimeQ日历时_是用“从一个标准时间点到此时的旉l过的秒?#8221;来表C的旉。这个标准时间点对不同的~译器来说会有所不同Q但对一个编译系l来 _q个标准旉Ҏ不变的,该编译系l中的时间对应的日历旉都通过该标准时间点来衡量,所以可以说日历旉?#8220;相对旉”Q但是无Z在哪一个时区, 在同一时刻对同一个标准时间点来说Q日历时间都是一L?nbsp;
epochQ?nbsp; 旉炏V时间点在标准C/C++中是一个整敎ͼ它用此时的时间和标准旉点相差的U数Q即日历旉Q来表示?nbsp;
clock tickQ时钟计时单元(而不把它叫做旉滴答ơ数Q,一个时钟计时单元的旉长短是由CPU控制的。一个clock tick不是CPU的一个时钟周期,而是C/C++的一个基本计时单位?nbsp;
我们可以使用ANSI标准库中的time.h头文件。这个头文g中定义的旉和日期所使用的方法,无论是在l构定义Q还是命名,都具有明昄C语言风格。下面,我将说明在C/C++中怎样使用日期的时间功能?nbsp;
2Q?计时
C/C++中的计时函数是clock()Q而与其相关的数据cd是clock_t。在MSDN中,查得对clock函数定义如下Q?nbsp;
clock_t clock( void );
q?个函数返回从“开启这个程序进E?#8221;?#8220;E序中调用clock()函数”时之间的CPU旉计时单元Qclock tickQ数Q在MSDN中称之ؓ挂钟旉Qwal-clockQ。其中clock_t是用来保存时间的数据cdQ在time.h文g中,我们可以扑ֈ?它的定义Q?nbsp;
#ifndef _CLOCK_T_DEFINED
typedef long clock_t;
#define _CLOCK_T_DEFINED
#endif
很明显,clock_t是一个长整Ş数。在time.h文g中,q定义了一个常量CLOCKS_PER_SECQ它用来表示一U钟会有多少个时钟计时单元,其定义如下:
#define CLOCKS_PER_SEC ((clock_t)1000)
可以看到每过千分之一U(1毫秒Q,调用clockQ)函数q回的值就?。下面D个例子,你可以用公式clock()/CLOCKS_PER_SEC来计一个进E自w的q行旉Q?nbsp;
void elapsed_time()
{
printf("Elapsed time:%u secs.\n",clock()/CLOCKS_PER_SEC);
}
当然Q你也可以用clock函数来计你的机器运行一个@环或者处理其它事件到底花了多时_
#include “stdio.h”
#include “stdlib.h”
#include “time.h”
int main( void )
{
long i = 10000000L;
clock_t start, finish;
double duration;
/* 量一个事件持l的旉*/
printf( "Time to do %ld empty loops is ", i );
start = clock();
while( i-- ) ;
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
printf( "%f seconds\n", duration );
system("pause");
}
在笔者的机器上,q行l果如下Q?nbsp;
Time to do 10000000 empty loops is 0.03000 seconds
上面我们看到旉计时单元的长度ؓ1毫秒Q那么计时的_ֺ也ؓ1毫秒Q那么我们可不可以通过改变CLOCKS_PER_SEC的定义,通过把它定义的大一些,从而计时_ֺ更高呢?通过试Q你会发现这h不行的。在标准C/C++中,最的计时单位是一毫秒?nbsp;
3Q与日期和时间相关的数据l构
在标准C/C++中,我们可通过tml构来获得日期和旉Qtml构在time.h中的定义如下Q?nbsp;
#ifndef _TM_DEFINED
struct tm {
int tm_sec; /* U?– 取值区间ؓ[0,59] */
int tm_min; /* ?- 取值区间ؓ[0,59] */
int tm_hour; /* ?- 取值区间ؓ[0,23] */
int tm_mday; /* 一个月中的日期 - 取值区间ؓ[1,31] */
int tm_mon; /* 月䆾Q从一月开始,0代表一月) - 取值区间ؓ[0,11] */
int tm_year; /* q䆾Q其值等于实际年份减?900 */
int tm_wday; /* 星期 – 取值区间ؓ[0,6]Q其?代表星期天,1代表星期一Q以此类?*/
int tm_yday; /* 从每q的1?日开始的天数 – 取值区间ؓ[0,365]Q其?代表1?日,1代表1?日,以此cL */
int tm_isdst; /* 夏o时标识符Q实行夏令时的时候,tm_isdst为正。不实行夏o时的q候,tm_isdst?Q不了解情况Ӟtm_isdst()?/
};
#define _TM_DEFINED
#endif
ANSI C标准UC用tml构的这U时间表CZؓ分解旉(broken-down time)?nbsp;
而日历时_Calendar TimeQ是通过time_t数据cd来表C的Q用time_t表示的时_日历旉Q是从一个时间点Q例如:1970q?????U)到此时的U数。在time.h中,我们也可以看到time_t是一个长整型敎ͼ
#ifndef _TIME_T_DEFINED
typedef long time_t; /* 旉?*/
#define _TIME_T_DEFINED /* 避免重复定义 time_t */
#endif
?家可能会产生疑问Q既然time_t实际上是长整型,到未来的某一天,从一个时间点Q一般是1970q?????U)到那时的U数Q即日历旉Q?出了长整Ş所能表C的数的范围怎么办?对time_t数据cd的值来_它所表示的时间不能晚?038q??8?9?4?7U。ؓ了能够表C?更久q的旉Q一些编译器厂商引入?4位甚x长的整Ş数来保存日历旉。比如微软在Visual C++中采用了__time64_t数据cd来保存日历时_q过_time64()函数来获得日历时_而不是通过使用32位字的time()?敎ͼQ这样就可以通过该数据类型保?001q?????U(不包括该旉点)之前的时间?nbsp;
在time.h头文件中Q我们还可以看到一些函敎ͼ它们都是以time_t为参数类型或q回值类型的函数Q?nbsp;
double difftime(time_t time1, time_t time0);
time_t mktime(struct tm * timeptr);
time_t time(time_t * timer);
char * asctime(const struct tm * timeptr);
char * ctime(const time_t *timer);
此外Qtime.hq提供了两种不同的函数将日历旉Q一个用time_t表示的整敎ͼ转换为我们^时看到的把年月日时分U分开昄的时间格式tmQ?nbsp;
struct tm * gmtime(const time_t *timer);
struct tm * localtime(const time_t * timer);
?q查阅MSDNQ我们可以知道Microsoft C/C++ 7.0中时间点的|time_t对象的|是从1899q?2?1???U到该时间点所l过的秒敎ͼ而其它各U版本的Microsoft C/C++和所有不同版本的Visual C++都是计算的从1970q?????U到该时间点所l过的秒数?nbsp;
4Q与日期和时间相关的函数及应?nbsp;
在本节,我将向大家展C怎样利用time.h中声明的函数Ҏ间进行操作。这些操作包括取当前旉、计时间间隔、以不同的Ş式显C时间等内容?nbsp;
4.1 获得日历旉
我们可以通过time()函数来获得日历时_Calendar TimeQ,其原型ؓQ?br>time_t time(time_t * timer);
?果你已经声明了参数timerQ你可以从参数timerq回现在的日历时_同时也可以通过q回D回现在的日历旉Q即从一个时间点Q例如:1970q?1????U)到现在此时的U数。如果参CؓI(NULQ,函数只通过q回D回现在的日历旉Q比如下面这个例子用来显C当前的日历旉Q?
#include "time.h"
#include "stdio.h"
int main(void)
{
struct tm *ptr;
time_t lt;
lt =time(NUL);
printf("The Calendar Time now is %d\n",lt);
return 0;
}
q行的结果与当时的时间有养I我当时运行的l果是:
The Calendar Time now is 1122707619
其中1122707619是我运行程序时的日历时间。即?970q?????U到此时的秒数?nbsp;
4.2 获得日期和时?nbsp;
q里说的日期和时间就是我们^时所说的q、月、日、时、分、秒{信息。从W?节我们已l知道这些信息都保存在一个名为tm的结构体中,那么如何一个日历时间保存ؓ一个tml构的对象呢Q?nbsp;
其中可以使用的函数是gmtime()和localtime()Q这两个函数的原型ؓQ?nbsp;
struct tm * gmtime(const time_t *timer);
struct tm * localtime(const time_t * timer);
?中gmtime()函数是将日历旉转化Z界标准时_x林尼L_Qƈq回一个tml构体来保存q个旉Q而localtime()函数是将日历 旉转化为本地时间。比如现在用gmtime()函数获得的世界标准时间是2005q??0??8?0U,那么我用localtime()函数?中国地区获得的本地时间会比世界标准时间晚8个小Ӟ?005q??0?5?8?0U。下面是个例子:
#include "time.h"
#include "stdio.h"
int main(void)
{
struct tm *local;
time_t t;
t=time(NUL);
local=localtime(&t);
printf("Local hour is: %d\n",local->tm_hour);
local=gmtime(&t);
printf("UTC hour is: %d\n",local->tm_hour);
return 0;
}
q行l果是:
Local hour is: 15
UTC hour is: 7
4.3 固定的时间格?nbsp;
我们可以通过asctime()函数和ctime()函数时间以固定的格式显C出来,两者的q回值都是char*型的字符丌Ӏ返回的旉格式为:
星期?月䆾 日期 ??U?q\n\0
例如QWed Jan 02 02:03:55 1980\n\0
其中\n是一个换行符Q\0是一个空字符Q表C字W串l束。下面是两个函数的原型:
char * asctime(const struct tm * timeptr);
char * ctime(const time_t *timer);
?中asctime()函数是通过tml构来生成具有固定格式的保存旉信息的字W串Q而ctime()是通过日历旉来生成时间字W串。这L话, asctimeQ)函数只是把tml构对象中的各个域填到时间字W串的相应位|就行了Q而ctimeQ)函数需要先参照本地的时间设|,把日历时间{化ؓ 本地旉Q然后再生成格式化后的字W串。在下面Q如果t是一个非I的time_t变量的话Q那么:
printf(ctime(&t));
{h于:
struct tm *ptr;
ptr=localtime(&t);
printf(asctime(ptr));
那么Q下面这个程序的两条printf语句输出的结果就是不同的了(除非你将本地时区设ؓ世界标准旉所在的时区Q:
#include "time.h"
#include "stdio.h"
int main(void)
{
struct tm *ptr;
time_t lt;
lt =time(NUL);
ptr=gmtime(<);
printf(asctime(ptr));
printf(ctime(<));
return 0;
}
q行l果Q?nbsp;
Sat Jul 30 08:43:03 2005
Sat Jul 30 16:43:03 2005
4.4 自定义时间格?nbsp;
我们可以使用strftimeQ)函数时间格式化为我们想要的格式。它的原型如下:
size_t strftime(
char *strDest,
size_t maxsize,
const char *format,
const struct tm *timeptr
);
我们可以Ҏformat指向字符串中格式命o把timeptr中保存的旉信息攑֜strDest指向的字W串中,最多向strDest中存放maxsize个字W。该函数q回向strDest指向的字W串中放|的字符数?nbsp;
?数strftime()的操作有些类gsprintf()Q识别以癑ֈ?%)开始的格式命o集合Q格式化输出l果攑֜一个字W串中。格式化命o说明?strDest中各U日期和旉信息的确切表C方法。格式串中的其他字符原样放进串中。格式命令列在下面,它们是区分大写的?nbsp;
%a 星期几的?nbsp;
%A 星期几的全称
%b 月分的简?nbsp;
%B 月䆾的全U?nbsp;
%c 标准的日期的旉?nbsp;
%C q䆾的后两位数字
%d 十进制表C的每月的第几天
%D ??q?nbsp;
%e 在两字符域中Q十q制表示的每月的W几?nbsp;
%F q???nbsp;
%g q䆾的后两位数字Q用基于周的年
%G q分Q用基于周的年
%h 写的月䆾?nbsp;
%H 24时制的时
%I 12时制的时
%j 十进制表C的每年的第几天
%m 十进制表C的月䆾
%M 十时制表C的分钟?nbsp;
%n 新行W?nbsp;
%p 本地的AM或PM的等hC?nbsp;
%r 12时的时?nbsp;
%R 昄时和分钟:hh:mm
%S 十进制的U数
%t 水^制表W?nbsp;
%T 昄时分U:hh:mm:ss
%u 每周的第几天Q星期一为第一?Qg0?Q星期一?Q?nbsp;
%U W年的第几周Q把星期日做为第一天(g0?3Q?nbsp;
%V 每年的第几周Q用基于周的年
%w 十进制表C的星期几(g0?Q星期天?Q?nbsp;
%W 每年的第几周Q把星期一做ؓW一天(g0?3Q?nbsp;
%x 标准的日期串
%X 标准的时间串
%y 不带世纪的十q制q䆾Qg0?9Q?nbsp;
%Y 带世U部分的十进制年?nbsp;
%zQ?Z 时区名称Q如果不能得到时区名U则q回I字W?nbsp;
%% 癑ֈ?nbsp;
如果xC现在是几点了,q以12时制显C,p下面q段E序Q?nbsp;
#include “time.h”
#include “stdio.h”
int main(void)
{
struct tm *ptr;
time_t lt;
char str[80];
lt=time(NUL);
ptr=localtime(<);
strftime(str,100,"It is now %I %p",ptr);
printf(str);
return 0;
}
其运行结果ؓQ?nbsp;
It is now 4PM
而下面的E序则显C当前的完整日期Q?nbsp;
#include <stdio.h>
#include <time.h>
void main( void )
{
struct tm *newtime;
char tmpbuf[128];
time_t lt1;
time( <1 );
newtime=localtime(<1);
strftime( tmpbuf, 128, "Today is %A, day %d of %B in the year %Y.\n", newtime);
printf(tmpbuf);
}
q行l果Q?nbsp;
Today is Saturday, day 30 of July in the year 2005.
4.5 计算持箋旉的长?nbsp;
有时候在实际应用中要计算一个事件持l的旉长度Q比如计打字速度。在W?节计旉分中Q我已经用clock函数举了一个例子。Clock()函数可以_到毫U。同Ӟ我们也可以用difftime()函数Q但它只能精到U。该函数的定义如下:
double difftime(time_t time1, time_t time0);
虽然该函数返回的以秒计算的时间间隔是doublecd的,但这q不说明该时间具有同double一L_度,q是由它的参数觉得的Qtime_t是以Uؓ单位计算的)。比如下面一D늨序:
#include "time.h"
#include "stdio.h"
#include "stdlib.h"
int main(void)
{
time_t start,end;
start = time(NUL);
system("pause");
end = time(NUL);
printf("The pause used %f seconds.\n",difftime(end,start));//<-
system("pause");
return 0;
}
q行l果为:
hL键l? . .
The pause used 2.000000 seconds.
hL键l? . .
可以惛_Q暂停的旉q不那么巧是整整2U钟。其实,你将上面E序的带?#8220;//<-”注释的一行用下面的一行代码替换:
printf("The pause used %f seconds.\n",end-start);
其运行结果是一L?nbsp;
4.6 分解旉转化为日历时?nbsp;
q里说的分解旉是以年、月、日、时、分、秒{分量保存的旉l构Q在C/C++中是tml构。我们可以用mktimeQ)函数用tml构表示的时间{化ؓ日历旉。其函数原型如下Q?nbsp;
time_t mktime(struct tm * timeptr);
其返回值就是{化后的日历时间。这h们就可以先制定一个分解时_然后对这个时间进行操作了Q下面的例子可以计算?997q??日是星期几:
#include "time.h"
#include "stdio.h"
#include "stdlib.h"
int main(void)
{
struct tm t;
time_t t_of_day;
t.tm_year=1997-1900;
t.tm_mon=6;
t.tm_mday=1;
t.tm_hour=0;
t.tm_min=0;
t.tm_sec=1;
t.tm_isdst=0;
t_of_day=mktime(&t);
printf(ctime(&t_of_day));
return 0;
}
q行l果Q?nbsp;
Tue Jul 01 00:00:01 1997
现在注意了,有了mktime()函数Q是不是我们可以操作现在之前的Q何时间呢Q你可以通过q种办法出1945q??5h星期几吗Q答案是否定的。因个时间在1970q??日之前,所以在大多数编译器中,q样的程序虽然可以编译通过Q但q行时会异常l止?
5Qȝ
本文介绍了标准C/C++中的有关日期和时间的概念Qƈ通过各种实例讲述了这些函数和数据l构的用方法。笔者认为,和时间相关的一些概忉|相当重要的,理解q些概念是理解各U时间格式的转换的基Q更是应用这些函数和数据l构的基?/p>
Z昄自己的技巧,也在自己的程序中用过几次。渐渐发现这L技巧带来的好处是有代h的,破坏了程序的l构化设计,E序变得很难读,其Ҏ手来说。终于明白这U技巧不q是一U调xQ在数情况使用几次Q可以简化对问题的处理。如果把调味拿来当饭吃,一定会本末倒置Q写出的E序会呈现营M良之状?/p>
事实上,longjmp和setjmp玩得熟不熟与是不是C语言高手Q不是因果关pR但是,如果可以套用那位高手的话Q我倒想说如果函数指针玩得不熟,׃要自UCؓC语言高手。ؓ什么这么说呢,函数指针有那么复杂吗Q当然不是,M一个稍有编E常识的人,不管他懂不懂C语言Q在10分钟内,我想他一定可以明白C语言中的函数指针是怎么回事?/p>
原因在于Q难的不是函数指针的概念和语法本w,而是在什么时候,什么地方该使用它。函数指针不仅是语法上的问题Q更重要的是它是一个设计范畴。真正的高手当然不单应该懂得语法层面上的技巧,更应该懂得设计上的方法。不懂设计,能算高手吗?怀疑我在夸大其辞吗Q那我们先看看函数指针与哪些设计Ҏ有关Q?/p>
与分层设计有兟?/strong>分层设计早就不是什么新的概念,分层的好处是众所周知的,比较明显好处是化复杂度、隔d化。采用分层设计,每层都只需兛_自己的东西,q减了pȝ的复杂度Q层与层之间的交互仅限于一个很H的接口Q只要接口不变,某一层的变化不会影响其它层,q隔M变化?/p>
分层的一般原则是Q上层可以直接调用下层的函数Q下层则不能直接调用上层的函数。这句话说来单,在现实中Q下层常常要反过来调用上层的函数。比如你在拷贝文件时Q在界面层调用一个拷贝文件函数。界面层是上层,拯文g函数是下层,上层调用下层Q理所当然。但是如果你惛_拯文g时还要更新进度条Q问题就来了。一斚wQ只有拷贝文件函数才知道拯的进度,但它不能L新界面的q度条。另外一斚wQ界面知道如何去更新q度条,但它又不知道拯的进度。怎么办?常见的做法,是界面讄一个回调函数给拯文g函数Q拷贝文件函数在适当的时候调用这个回调函数来通知界面更新状态?/p>
与抽象有兟?/strong>抽象是面向对象中最重要的概念之一Q也是面向对象威力强大之处。面向对象只是一U思想Q大安知道Q用C语言一样可以实现面向对象的~程。这可不是ؓ了赶旉Q而是一U实用的Ҏ。如果你Ҏ表示怀疑,可以ȝ看GTK+、linux kernel{开源代码?/p>
接口是最高的抽象。在linux kernel里面Q接口的概念无处不在Q像虚拟文gpȝ(VFS)Q它定义一个文件系l的接口Q只要按照这U接口的规范Q你可以自己开发一个文件系l挂上去。设备驱动程序更是如此,不同的设备驱动程序有自己一套不同的接口规范。在自己开发设备开发驱动程序时Q只要遵循相应的接口规范p了。接口在C语言中如何表C?很简单,是一l函数指针?/p>
与接口与实现分开有关。针Ҏ口编E,而不是针对实现编E,此ؓ《设计模式》的W一条设计准则。分开接口与实现的目标是要隔离变化。Y件是变化的,如果不能把变化的东西隔离开来,D牵一发而动全nQ代h巨大的。这是大家所不愿看到的?/p>
C语言既然可以实现面向对象的编E,自然可以利用设计模式来分L口与实现。像桥接模式、策略模式、状态模式、代理模式等{,在C语言中,无一不需要利用函数指针来实现?/p>
与松耦合原则有关。面向过E与面向对象相比Q之所以显得苍白无力,原因之一是它不像面向对象一P可以直观的把现实模型映射到计机中。面向过E讲的是层层控制Q而面向对象更的对象间的分工合作。现实世界中的对象处于层ơ关pȝ较少Q处于对{关pȝ居多。也是_对象间的交互往往是双向的。这会加强对象间的耦合性?/p>
耦合本n没有错,实际上耦合是必不可的Q没有耦合没有协作,对象之间无法形成一个整体,什么事也做不了。关键在于耦合要恰当,在实现预定功能的前提下,耦合要尽可能的松散。这Ppȝ的一部分变化对其它部分的影响会很?/p>
函数指针是解耦对象关pȝ最佛_器。Signal(如boost的signal和glib中的signal)机制是一个典型的例子Q一个对象自w的状态可能是在变化的Q或者会触发一些事ӞQ而其它对象关心它的变化。一旦该对象有变化发生,其它对象要执行相应的操作?/p>
如果该对象直接去调用其它对象的函敎ͼ功能是完成了Q但对象之间的耦合太紧了。如何把q种耦合降到最低呢Qsignal机制是很好的办法。它的原理大致如下:其它x该对象变化的对象d注册一个回调函数到该对象中。一旦该对象有变化发生,p用这些回调函数通知其它对象。功能同样实CQ但它们之间的耦合度降低了?/p>
在C语言中,要解决以上这些问题,不采用函数指针,是非常困难的。在~程中,如果你从没有惛_用函数指针,很难惛_你是一个C语言高手?/p>
(13)求从x位(高)到y位(低)间共有多个1
public static int FindChessNum(int x, int y, ushort k)
{
int re = 0;
for (int i = y; i <= x; i++)
{
re += ((k >> (i - 1)) & 1);
}
return re;
}
(14)
/*?2位数分解??位数处理后再合成32位数q回*/
DWORD GetDW(DWORD dw)
{
DWORD dwRet=0;
if (dw!=0)
{
BYTE b1=(dw>>24)&0xff,b2=(dw>>16)&0xff,b3=(dw>>8)&0xff,b4=dw&0xff;
//分别处理 b1,b2,b3,b4
dwRet=b1;
dwRet=(dwRet<<8)+b2;
dwRet=(dwRet<<8)+b3;
dwRet=(dwRet<<8)+b4;
return dwRet;
}
else{
return 0;
}
}
一个无W号数是不ؓ2^n-1(^为幂)Q?nbsp; x&(x+1)
最右侧0位改?位: x | (x+1)
二进制补码运公式:
-x = ~x + 1 = ~(x-1)
~x = -x-1
-(~x) = x+1
~(-x) = x-1
x+y = x - ~y - 1 = (x|y)+(x&y)
x-y = x + ~y + 1 = (x|~y)-(~x&y)
x^y = (x|y)-(x&y)
x|y = (x&~y)+y
x&y = (~x|y)-~x
x==y: ~(x-y|y-x)
x!=y: x-y|y-x
x< y: (x-y)^((x^y)&((x-y)^x))
x<=y: (x|~y)&((x^y)|~(y-x))
x< y: (~x&y)|((~x|y)&(x-y))//无符号x,y比较
x<=y: (~x|y)&((x^y)|~(y-x))//无符号x,y比较
使用位运的无分支代码:
计算l对?nbsp;
int abs( int x )
{
int y ;
y = x >> 31 ;
return (x^y)-y ;//or: (x+y)^y
}
W号函数Qsign(x) = -1, x<0; 0, x == 0 ; 1, x > 0
int sign(int x)
{
return (x>>31) | (unsigned(-x))>>31 ;//x=-2^31时失?^为幂)
}
三值比较:cmp(x,y) = -1, x<y; 0, x==y; 1, x > y
int cmp( int x, int y )
{
return (x>y)-(x-y) ;
}
doz=x-y, x>=y; 0, x<y
int doz(int x, int y )
{
int d ;
d = x-y ;
return d & ((~(d^((x^y)&(d^x))))>>31) ;
}
int max(int x, int y )
{
int m ;
m = (x-y)>>31 ;
return y & m | x & ~m ;
}
不用第三方交换x,y:
1.x ^= y ; y ^= x ; x ^= y ;
2.x = x+y ; y = x-y ; x = x-y ;
3.x = x-y ; y = y+x ; x = y-x ;
4.x = y-x ; x = y-x ; x = x+y ;
双g?x = a, x==b; b, x==a//常规~码为x = x==a ? b :a ;
1.x = a+b-x ;
2.x = a^b^x ;
下舍入到2的kơ方的倍数:
1.x & ((-1)<<k)
2.(((unsigned)x)>>k)<<k
上舍入:
1. t = (1<<k)-1 ; x = (x+t)&~t ;
2.t = (-1)<<k ; x = (x-t-1)&t ;
位计?l计1位的数量Q?nbsp;
1.
int pop(unsigned x)
{
x = x-((x>>1)&0x55555555) ;
x = (x&0x33333333) + ((x>>2) & 0x33333333 ) ;
x = (x+(x>>4)) & 0x0f0f0f0f ;
x = x + (x>>8) ;
x = x + (x>>16) ;
return x & 0x0000003f ;
}
2.
int pop(unsigned x) {
static char table[256] = { 0,1,1,2, 1,2,2,3, ...., 6,7,7,8 } ;
return table[x&0xff]+table[(x>>8)&0xff]+table[(x>>16)&0xff]+table[(x>>24)] ;
}
奇偶性计?
x = x ^ ( x>>1 ) ;
x = x ^ ( x>>2 ) ;
x = x ^ ( x>>4 ) ;
x = x ^ ( x>>8 ) ;
x = x ^ ( x>>16 ) ;
l果中位于x最低位Q对无符号x,l果的第i位是原数Wi位到最左侧位的奇偶?nbsp;
位反转:
unsigned rev(unsigned x)
{
x = (x & 0x55555555) << 1 | (x>>1) & 0x55555555 ;
x = (x & 0x33333333) << 2 | (x>>2) & 0x33333333 ;
x = (x & 0x0f0f0f0f) << 4 | (x>>4) & 0x0f0f0f0f ;
x = (x<<24) | ((x&0xff00)<<8) | ((x>>8) & 0xff00) | (x>>24) ;
return x ;
}
递增位反转后的数Q?nbsp;
unsigned inc_r(unsigned x)
{
unsigned m = 0x80000000 ;
x ^= m ;
if( (int)x >= 0 )
do { m >>= 1 ; x ^= m ; } while( x < m ) ;
return x ;
}
混选位Q?nbsp;
abcd efgh ijkl mnop ABCD EFGH IJKL MNOP->aAbB cCdD eEfF gGhH iIjJ kKlL mMnN oOpP
unsigned ps(unsigned x)
{
unsigned t ;
t = (x ^ (x>>8)) & 0x0000ff00; x = x ^ t ^ (t<<8) ;
t = (x ^ (x>>4)) & 0x00f000f0; x = x ^ t ^ (t<<4) ;
t = (x ^ (x>>2)) & 0x0c0c0c0c; x = x ^ t ^ (t<<2) ;
t = (x ^ (x>>1)) & 0x22222222; x = x ^ t ^ (t<<1) ;
return x ;
}
位压~:
选择q右Udx中对应于掩码m?位的?如:compress(abcdefgh,01010101)=0000bdfh
compress_left(x,m)操作与此cMQ但l果位在左边: bdfh0000.
unsigned compress(unsigned x, unsigned m)
{
unsigned mk, mp, mv, t ;
int i ;
x &= m ;
mk = ~m << 1 ;
for( i = 0 ; i < 5 ; ++i ) {
mp = mk ^ ( mk << 1) ;
mp ^= ( mp << 2 ) ;
mp ^= ( mp << 4 ) ;
mp ^= ( mp << 8 ) ;
mp ^= ( mp << 16 ) ;
mv = mp & m ;
m = m ^ mv | (mv >> (1<<i) ) ;
t = x & mv ;
x = x ^ t | ( t >> ( 1<<i) ) ;
mk = mk & ~mp ;
}
return x ;
}
位置换:
?2?位数表示从最低位开始的位的目标位置Q结果是一?2*5的位矩阵Q?nbsp;
该矩阵沿次对角U{|后??2位字p[5]存放?nbsp;
SAG(x,m) = compress_left(x,m) | compress(x,~m) ;
准备工作Q?nbsp;
void init( unsigned *p ) {
p[1] = SAG( p[1], p[0] ) ;
p[2] = SAG( SAG( p[2], p[0]), p[1] ) ;
p[3] = SAG( SAG( SAG( p[3], p[0] ), p[1]), p[2] ) ;
p[4] = SAG( SAG( SAG( SAG( p[4], p[0] ), p[1]) ,p[2]), p[3] ) ;
}
实际|换Q?nbsp;
int rep( unsigned x ) {
x = SAG(x,p[0]);
x = SAG(x,p[1]);
x = SAG(x,p[2]);
x = SAG(x,p[3]);
x = SAG(x,p[4]);
return x ;
}
二进制码到GRAY码的转换:
unsigned B2G(unsigned B )
{
return B ^ (B>>1) ;
}
GRAY码到二进制码:
unsigned G2B(unsigned G)
{
unsigned B ;
B = G ^ (G>>1) ;
B = G ^ (G>>2) ;
B = G ^ (G>>4) ;
B = G ^ (G>>8) ;
B = G ^ (G>>16) ;
return B ;
}
扑և最?字节的位|?
int zbytel( unsigned x )
{
static cahr table[16] = { 4,3,2,2, 1,1,1,1, 0,0,0,0, 0,0,0,0 } ;
unsigned y ;
y = (x&0x7f7f7f7f) + 0x7f7f7f7f ;
y = ~(y|x|0x7f7f7f7f) ;
return table[y*0x00204081 >> 28] ;//乘法可用UM和加完成
}
C\C++支持比较低阶的位q算Q在是众人皆知的了。每本C\C++的教U书都会说到q部分的内容Q不q都很简略,我想会有很多Z知道位运用在什么地斏V这个帖子就略说说位q算的用处,更进一步的用法要大家自己去体会。而主要说的是操作标志值方面?/p>
/****************************************/
#define BTI_MSK(bit) (1 << (bit))
#define BIT_SET(x,bit) ((x) |= BTI_MSK (bit))
#define BIT_CLR(x,bit) ((x) &= ~BTI_MSK (bit))
#define BIT_TST(x,bit) ((x) & BTI_MSK (bit))
/****************************************/
考虑一个事物、一个系l、或者一个程序可能会出现一U或者几U状态。ؓ了在不同的状态下Q作Z同的行ؓQ你可以讄一些标志|再根据标志值来做判断。比如C++的文件流Q你可以设定一些标志|ios::app, ios::ate, ios::binary, ios::in, ios::out, ios::truncQƈ且可以将它用|l合h创徏一个恰当的文g。你可能会将q些标志值定义ؓboolcdQ不q这栯是设|的标志g多,׃很浪费空间?br>
而假如定义一个整型数|unsigned int flags; 在现在的pȝQflags应该?2? ?,2,3....32位q行~号Q我们可以进行这L判断, 当位1?Ӟ表示用读方式打开文gQ当??Ӟ表示用写方式打开文gQ当??Ӟ用二q制方式打开文g....因ؓflags?2位,可以设|?2个不同的状态|也相当于32个boolcd。这样一斚w省了I间, 另一斚w也多了个好处Q就是如前面所说的Q可以将标志值组合v来?br>//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
好啦Q上面有点不清不楚的。下面看看到底怎么操作q些标志倹{?br>设想C++的类iosq样定义, 其实没有q个c,只有ios_basicc,typedef basic_ios<char> ios;
class ios
{
public:
enum { app = 0x0001, ate = 0x0002, binary = 0x0004,
in = 0x0008, out = 0x0010, trunc = 0x0020 };
....
private:
unsigned int flags;
};
注意上面enum语句中,每一个数值只?位是1Q其余是0Q这个很重要Q你可以它化成2q制看看?br>
现在flags相应的位讄?, 可以q样?nbsp;flags |= app。这个等于flags = flags | app, Z么呢? app只有1位是1Q其余是0Q因? | 1 = 0Q?nbsp;0 | 0 = 0Q?nbsp;q样0对应的位是不变的。? | 1 = 1, 1 | 0 = 1, 1对应的位不论原来是什么状态,都一定ؓ1。如果想要将几个位都讄?Q可以这样做 flags |= (app | ate | binary)。因为每个enum常数各有一位ؓ1, 与运之后就?位ؓ1Q就如上面的分析Q就可以那3位都讄?, 其余位不变。这个就是标志可以组合v来用的原因。也可以?l合hQ原因在?下面的数字是2q制)0001 + 0010 + 0100 = 0111 跟与q算l果一栗不q不提倡用+, 考虑(app | ate | binary)要是我不心写多了个标志|(app | ate | ate | binary)l果q是正确的,如果?的话Q就会生进位,l果׃错误。通常我们不知道原先已l组合了多少个标志gQ用或运会安全?br>
现在flags对应的位讄?, 可以q样?nbsp;flags &= ~app。相当于 flags = flags & (~app). app取反之后Q只?位是0Q其余是1Q做与运之后,1对应的位q不会改变,0对应的ؓ不管原来??Q都肯定?Q这样就对应的位设|了0。同样同时设|几个标志位可以q样做,flags &= ~(app | ate | binary)?br>
现在flags对应的位Q如果是1变?Q如果是0变?Q可以这样做 flags ^= app。同时设|几个标志位可以写成 flags ^= (app | ate | binary)。不再做分析了,不然太|嗦了。不q也l大家一个例子,你查查Ascii表,会发现对应的大小写字母是相差倒数W?位,可以用这L函数l一的将大写变成写Q小写变成大写?br>void xchgUppLow(string& letters)
{
const unsigned int mask = (1<<5);
for (size_t i=0; i<letters.length(); i++)
letters[i] ^= mask;
}
前提是输入的string一定要全是字母, 而要x操作字母Q可以在原来基础上加个判断?br>
好啦Q上面已l可以设|flags的对应位gQ要是判断呢Q可以这样写 if (flags & app) q样可以判断对应的位值是否ؓ1, 因ؓC\C++语言中非0q。app只有一位是1Q其余是0Q如? flags的对应位也是0Q在与操作下得到结?Q反之非0Q这样就可以判断标志位了?br>
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
上面关于标志值的操作׃l完毕。其实在C++中已l有了个bitset了,没有必要去自p行低阶的位运,上面的四个操作在bitset中分别叫做set, reset, flip, test。不q在C中,q样的代码还很常? 反正知道多点也没有坏处?br>
?nbsp;windows API ~程Q你也经怼到q样的标志|要互相组合,可以用|, 也可以用+(只是用|Q理׃面说?. 它的标志g是这样定义的Q不q用#define
#define WS_BORDER 0x0001
#define WS_CAPTION 0x0002
......
当初我就是想不明白ؓ什么可以用|或者用+来组合,现在知道了?br>
(注:上面出现的数字是我自׃的,到底实际怎么定义其实没有关系Q只要保证只有一位是1Q其余是0可以的? 因ؓ~程的时候用的是帔R|没有Lȝ接用数值的)
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
其实Q位q算q有很多用处。比如移位相当于乘除2的幂?不过通常~译器也乘?的幂C化成汇编的移位指令,所以没有必要不要这样卖弄了。汇~的UM指o有两l,分别针对有符号和无符L, 我猜惛_C\C++的同一UMq算针对有符h数和无符h数的不同Q会Ҏ情况~译成不同的汇编UM指oQ不q没有去证实), 其实UM更用得多的地ҎL造一个掩? 比如上面的mask = (1<<5);
q有&q算Q有时候可以用来求余数。比?nbsp;value & (1<<4 - 1) q相当于value的高位全变成0了,效果{于 value % 8.
q有值得一提的是^q算Q它有个很特D的性质。比?nbsp;A ^= B, 变成另一个数Q跟着再执行A ^= BQ又变回原来的数了,不信你可以列真D或者化逻辑式看看。就因ؓq个性质Q^有很多用途。比如加密,你将原文看成A, 用同一个B异或一ơ,q当于加密Q跟着在用B异或一ơ,相当于解密。不q这h很容易破解就是了。要是一个B不够Q还可以加个C, 比如A ^= B, A ^= C, A ^= C, A ^= B, 恢复原状?br>
下面一个小E序Q用异或交换两个数字?br>int x = 3;
int y = 4;
x ^= y;
y ^= x;
x ^= y;
其实何止交换数字Q连交换对象也可以的
template <typename T>
void swap(T& obj1, T& obj2)
{
const int sizeOfObj = sizeof(T);
char* pt1 = (char*)&obj1;
char* pt2 = (char*)&obj2;
for (size_t i=0; i<sizeOfObj; i++)
{
pt1[i] ^= pt2[i];
pt2[i] ^= pt1[i];
pt1[i] ^= pt2[i];
}
}
q有异或操作q可以用在图象的光栅操作。我们知道,颜色也是用二q制来表C的Q对颜色q行不同的位q算Q就可以得到不同的光栅。因为异或的Ҏ性质Q我们用异或操作的光栅画了副图,跟着再在原来的地方画一ơ,那副囑ְ刷除了。这样可以用来显C动画而不用保存原来的d信息。以前我写过个双人的贪食蛇,q了异或光栅。因景色是白色的Q也是?Q作A ^ 1 = A, 所以用dMơ是M讑֮的颜Ԍ再画一ơ就恢复。最有趣的是两蛇怺的时候,颜色也会作异或叠加,产生一U新的颜色了Q离开的时候也会自动恢复?br>//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
好啦Q够长了Q就停止吧。在最后再l大家一D代码,是用来看看对象在内存中的位值的。可以看看?br>string bitsOfUChar(unsigned char c)
{
const int numOfBitsInUChar = 8;
unsigned int mask = (1<<7);
string result(8, '0');
for (size_t i=0; i<numOfBitsInUChar; i++)
{
if ( mask & c)
result[i] = '1';
mask >>= 1;
}
return result;
}
template <typename T>
string bitsInMemory(const T& obj)
{
int sizeOfObj = sizeof(obj);
unsigned char* pt = (unsigned char*)&obj;
string result;
for (size_t i=0; i<sizeOfObj; i++)
{
result += bitsOfUChar(pt[i]);
result += ' ';
}
return result;
}
比如bitsInMemory(12)Q会输出00001100 00000000 00000000 00000000, 我就知道我自q机器是小N序的了?br>