C++函数的学习
1 sprintf_s函数用法
函数功能:将数据格式化输出到字符串
函数原型:
int sprintf_s(
char *buffer,
size_t sizeOfBuffer,
const char *format [,
argument] ...
);
需要包含的头文件:stdio.h
注意:
sprintf_s()是sprintf()的安全版本,通过指定缓冲区长度来避免sprintf()存在的溢出风险
程序示例:
charfilename[1024];//需要预先分配缓冲区
char path1[128] ="D:\\Program\\Tesseract-OCR\\tesseract.exe"; //文件路径\要改成\\
char path2[128] = "D:\\Program\\Tesseract-OCR\\";
char path3[128] = "D:\\Program\\Tesseract-OCR\\txt";
char path4[128] = "-l chi_sim";
sprintf_s(filename,"%s %s %s %s",path1,filepath,path3,path4);
system(filename);
_sprintf_s
http://msdn.microsoft.com/zh-cn/library/ce3zzk1k(v=vs.110).aspx
一般文本例程映射
TCHAR.H 实例 | 未定义的 _UNICODE _MBCS | 定义的 _MBCS | 定义的 _UNICODE |
_stprintf_s | sprintf_s | sprintf_s | swprintf_s |
_stprintf_s_l | _sprintf_s_l | _sprintf_s_l | _swprintf_s_l |
TCHAR.H 实例既适合UNICODE有适合ASCII
_stprintf_s的用法
_stprintf_s和_stscanf_s
MSDN上的定义:
TCHAR.Hroutine _UNICODE& _MBCS notdefined _MBCSdefined _UNICODE defined
_stprintf_s sprintf_s sprintf_s swprintf_s
_stscanf_s sscanf_s sscanf_s swscanf_s
从上我们可以看出,_stprintf_s和_stscanf_s是为适应不同编码而定义的两个宏,在不同的编码环境下他们所表示的函数是不同的。
1.int sprintf_s( char *buffer, size_tsizeOfBuffer, const char *format [, argument] ... );
这个函数的主要作用是将若干个argument按照format格式存到buffer中,其中
buffer
输出的字符
sizeOfBuffer
buffer的长度
format
格式字符串,比如%s
argument
可选参数
2.int sscanf_s( const char *buffer,const char *format [, argument ] ... );
这个函数的主要作用是从buffer中读取指定格式(format)的字符到相应的argument中,其中
buffer
字符数组
format
格式字符串,比如%s
argument
可选参数
_stprintf_s(szT,_countof(szT), _T("%d"), nValue); //把整数型转化成字符串其中参数_T("%d")代表转化的类型;
_stprintf_s(szT,_countof(szT), _T("%f"), dValue);//把DOUBLE型转化成字符串
2 求CString指针的长度;
CString a;
a.Getlength(); //求字符串a的长度;
intGetLength( ) const;
返回字符串的长度,不包含结尾的空字符。
例:csStr="ABCDEF中文123456";
printf("%d",csStr.GetLength()); //16
3 LPSTR、LPCSTR、LPTSTR、LPCTSTR的来源及意义
UNICODE:(采用双字节对字符进行编码;统一的字符编码标准)它是用两个字节表示一个字符的方法。比如字符'A'在ASCII下面是一个字符,可'A'在UNICODE下面是两个字符,高字符用0填充,而且汉字'程'在ASCII下面是两个字节,而在UNICODE下仍旧是两个字节。UNICODE的用处就是定长表示世界文字,据统计,用两个字节可以编码现存的所有文字而没有二义。
MBCS,它是多字节字符集,它是不定长表示世界文字的编码。MBCS表示英文字母时就和ASCII一样(这也是我们容易把MBCS和ASCII搞混的原因),但表示其他文字时就需要用多字节。
那WINDOWS下面的程序设计可以支持MBCS和UNICODE两种编码的字符串,具体用哪种就看你定义了MBCS宏还是UNICODE宏。MBCS宏对应的字符串指针是char*也就是LPSTR,UNICODE对应的指针是unsigned short*也就是LPWSTR,为了写程序方便微软定义了类型LPTSTR,在MBCS下他就是char*, 在UNICODE下它是unsigned char*,这样你就可以重定义一个宏进行不同字符集的转换了。
LPSTR、LPCSTR、LPTSTR、LPCTSTR的意义:
LPSTR:32bit指针指向一个字符串,每个字符占1字节
LPCSTR:32-bit指针指向一个常(#add第3个字母C表示constant)字符串,每个字符占1字节
LPTSTR:32-bit指针每字符可能占1字节或2字节,取决于Unicode是否定义
LPCTSTR:32-bit指针指向一个常字符串,每字符可能占1字节或2字节,取决于Unicode是否定义
Windows使用两种字符集ANSI和UNICODE,前者就是通常使用的单字节方式,但这种方式处理象中文这样的双字节字符不方便,容易出现半个汉字的情况。而后者是双字节方式,方便处理双字节字符。
WindowsNT 的所有与字符有关的函数都提供两种方式的版本,而Windows9x只支持ANSI方式。_T一般同字常数相关,如_T("Hello"。如果你编译一个程序为ANSI方式,_T实际不起任何作用。而如果编译一个程序为UNICODE方式,则编译器会把"Hello"字符串以UNICODE方式保存。
_T 和L的区别在于,L不管你是以什么方式编译,一律UNICODE方式保存.
L是表示字符串资源为Unicode的。
比如
wchar_t Str[] = L"Hello World!";
这个就是双子节存储字符了。
_T是一个适配的宏~
当
#ifdef _UNICODE的时候
_T就是L
没有#ifdef _UNICODE的时候
_T就是ANSI的。
比如
LPTSTR lpStr = new TCHAR[32];
TCHAR* szBuf = _T("Hello");
以上两句使得无论是在UNICODE编译条件下都是正确编译的。
而且MS推荐你使用相匹配的字符串函数。
比如处理LPTSTR或者LPCTSTR的时候,不要用strlen,而是要用_tcslen
否则在UNICODE的编译条件下,strlen不能处理 wchar_t*的字符串。
T是非常有意思的一个符号(TCHAR、LPCTSTR、LPTSTR、_T()、_TEXT()...),它表示使用一种中间类型,既不明确表示使用 MBCS,也不明确表示使用 UNICODE。那到底使用哪种字符集?编译的时候才决定
在vc++中有着各种字符串的表示法,如您所说。
首先char* 是指向ANSI字符数组的指针,其中每个字符占据8位(有效数据是除掉最高位的其他7位),这里保持了与传统的C,C++的兼容。
LP的含义是长指针(long pointer)。
LPSTR是一个指向以‘\0’结尾的ANSI字符数组的指针,与char*可以互换使用,在win32中较多地使用 LPSTR。而LPCSTR中增加的‘C’的含义是“CONSTANT”(常量),表明这种数据类型的实例不能被使用它的API函数改变,除此之外,它与LPSTR是等同的。
为了满足程序代码国际化的需要,业界推出了Unicode标准,它提供了一种简单和一致的表达字符串的方法,所有字符中的字节都是16位的值,其数量也可以满足差不多世界上所有书面语言字符的编码需求,开发程序时使用Unicode(类型为wchar_t)是一种被鼓励的做法。
LPWSTR与LPCWSTR由此产生,它们的含义类似于LPSTR与LPCSTR,只是字符数据是16位的wchar_t而不是char。
然后为了实现两种编码的通用,提出了TCHAR的定义:
如果定义_UNICODE,声明如下:typedef wchar_t TCHAR;
如果没有定义_UNICODE,则声明如下:typedef char TCHAR;
LPTSTR和LPCTSTR中的含义就是每个字符是这样的TCHAR。
CString类中的字符就是被声明为TCHAR类型的,它提供了一个封装好的类供用户方便地使用。
如果您还需要进一步的信息,请参看http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_data_type_mappings.asp等其他有关信息。
LPSTR、LPCSTR、LPTSTR、LPCTSTR之间的转换:
如何理解LPCTSTR类型?
L表示long指针
这是为了兼容Windows 3.1等16位操作系统遗留下来的,在win32中以及其他的32位操作系统中, long指针和near指针及far修饰符都是为了兼容的作用。没有实际意义。
P表示这是一个指针
C表示是一个常量
T表示在Win32环境中,有一个_T宏 ,表示既适合多字节有适合UNICODE的。
这个宏用来表示你的字符是否使用UNICODE,如果你的程序定义了UNICODE或者其他相关的宏,那么这个字符或者字符串将被作为UNICODE字符串,否则就是标准的ANSI字符串。
STR表示这个变量是一个字符串
所以LPCTSTR就表示一个指向常固定地址的可以根据一些宏定义改变语义的字符串。
同样, LPCSTR就只能是一个ANSI字符串,在程序中我们大部分时间要使用带T的类型定义。
LPCTSTR == const TCHAR *
CString 和 LPCTSTR可以说通用。原因在于CString定义的自动类型转换,没什么奇特的,最简单的C++操作符重载而已。
常量字符串ansi和unicode的区分是由宏_T来决定的。但是用_T("abcd")时,字符串"abcd"就会根据编译时的是否定义_UNICODE来决定是char*还是 w_char*。同样,TCHAR也是相同目的字符宏。看看定义就明白了。简单起见,下面只介绍 ansi的情况,unicode可以类推。
ansi情况下,LPCTSTR就是 const char*,是常量字符串(不能修改的)。
而LPTSTR就是 char*,即普通字符串(非常量,可修改的)。
这两种都是基本类型,而CString是 C++类,兼容这两种基本类型是最起码的任务了。
由于const char*最简单(常量,不涉及内存变更,操作迅速),CString直接定义了一个类型转换函数operator LPCTSTR() {......},直接返回他所维护的字符串。
当你需要一个const char*而传入了CString时, C++编译器自动调用CString重载的操作符 LPCTSTR()来进行隐式的类型转换。
当需要CString ,而传入了 const char*时(其实 char* 也可以),C++编译器则自动调用CString的构造函数来构造临时的 CString对象。
因此CString和 LPCTSTR 基本可以通用。
但是 LPTSTR又不同了,他是 char*,意味着你随时可能修改里面的数据,这就需要内存管理了(如字符串变长,原来的存贮空间就不够了,则需要重新调整分配内存)。
所以不能随便的将 const char*强制转换成 char*使用。
楼主举的例子
LPSTR lpstr = (LPSTR)(LPCTSTR)string;
就是这种不安全的使用方法。
这个地方使用的是强制类型转换,你都强制转换了,C++编译器当然不会拒绝你,但同时他也认为你确实知道自己要做的是什么。因此是不会给出警告的。
强制的任意类型转换是C(++)的一项强大之处,但也是一大弊端。这一问题在 vc6以后的版本(仅针对vc而言)中得到逐步的改进(你需要更明确的类型转换声明)。
其实在很多地方都可以看到类似
LPSTR lpstr = (LPSTR)(LPCTSTR)string;
地用法,这种情况一般是函数的约束定义不够完善的原因,比如一个函数接受一个字符串参数的输入,里面对该字符串又没有任何的修改,那么该参数就应该定义成 const char*,但是很多初学者弄不清const地用法,或者是懒,总之就是随意写成了 char* 。这样子传入CString时就需要强制的转换一下。
这种做法是不安全的,也是不被建议的用法,你必须完全明白、确认该字符串没有被修改。
CString 转换到 LPTSTR (char*),预定的做法是调用CString的GetBuffer函数,使用完毕之后一般都要再调用ReleaseBuffer函数来确认修改 (某些情况下也有不调用ReleaseBuffer的,同样你需要非常明确为什么这么做时才能这样子处理,一般应用环境可以不考虑这种情况)。
同时需要注意的是,在GetBuffer和 ReleaseBuffer之间,CString分配了内存交由你来处理,因此不能再调用其他的CString函数。
CString 转LPCTSTR:
CString cStr;
const char *lpctStr = (LPCTSTR)cStr;
LPCTSTR转CString:
LPCTSTR lpctStr;
CString cStr = lpctStr;
4 UINT 是一个无符号的整形变量
5[转]C/C++ define 用法
5.在大规模的开发过程中,特别是跨平台和系统的软件里,define最重要的功能是条件编译。... 2
1.简单的define定义
#define MAXTIME 1000
一个简单的MAXTIME就定义好了,它代表1000,如果在程序里面写
if(i<MAXTIME){.........}
编译器在处理这个代码之前会对MAXTIME进行处理替换为1000。
这样的定义看起来类似于普通的常量定义CONST,但也有着不同,因为define的定义更像是简单的文本替换,而不是作为一个量来使用,这个问题在下面反映的尤为突出。
2.define的“函数定义”
define可以像函数那样接受一些参数,如下
#define max(x,y)(x)>(y)?(x):(y);
这个定义就将返回两个数中较大的那个,看到了吗?因为这个“函数”没有类型检查,就好像一个函数模板似的,当然,它绝对没有模板那么安全就是了。可以作为一个简单的模板来使用而已。
但是这样做的话存在隐患,例子如下:
#define Add(a,b) a+b;
在一般使用的时候是没有问题的,但是如果遇到如:c * Add(a,b) * d的时候就会出现问题,代数式的本意是a+b然后去和c,d相乘,但是因为使用了define(它只是一个简单的替换),所以式子实际上变成了
c*a + b*d
另外举一个例子:
#define pin (int*);
pin a,b;
本意是a和b都是int型指针,但是实际上变成int* a,b;
a是int型指针,而b是int型变量。
这是应该使用typedef来代替define,这样a和b就都是int型指针了。
所以我们在定义的时候,养成一个良好的习惯,建议所有的层次都要加括号。
3.宏的单行定义
#define A(x) T_##x
#define B(x) #@x
#define C(x) #x
我们假设:x=1,则有:
A(1)------〉T_1
B(1)------〉'1'
C(1)------〉"1"
(这里参考了 hustli的文章)
4.define的多行定义
define可以替代多行的代码,例如MFC中的宏定义(非常的经典,虽然让人看了恶心)
#define MACRO(arg1, arg2) do {\
/* declarations */ \
stmt1; \
stmt2; \
/* ... */ \
} while(0) /* (no trailing ; )*/
关键是要在每一个换行的时候加上一个"\
修补了几个bug
5.在大规模的开发过程中,特别是跨平台和系统的软件里,define最重要的功能是条件编译。
就是:
#ifdef WINDOWS
......
......
#endif
#ifdef LINUX
......
......
#endif
可以在编译的时候通过#define设置编译环境
6.如何定义宏、取消宏
//定义宏
#define [MacroName][MacroValue]
//取消宏
#undef [MacroName]
普通宏
#define PI (3.1415926)
带参数的宏
#define max(a,b) ((a)>(b)?(a),(b))
关键是十分容易产生错误,包括机器和人理解上的差异等等。
7.条件编译
#ifdef XXX…(#else) …#endif
例如 #ifdef DV22_AUX_INPUT
#define AUX_MODE 3
#else
#define AUY_MODE 3
#endif
#ifndef XXX … (#else)… #endif
8.头文件(.h)可以被头文件或C文件包含;
重复包含(重复定义)
由于头文件包含可以嵌套,那么C文件就有可能包含多次同一个头文件,就可能出现重复定义的问题的。
通过条件编译开关来避免重复包含(重复定义)
例如
#ifndef __headerfileXXX__
#define __headerfileXXX__
…
文件内容
…
#endif
以上只是我从网络上搜集了一些关于define的一些用法,可能还不全面,而且#define的使用本来也存在这争议,如果你对#define的用法也很有兴趣,可以来参加我们的讨论(点击下面的链接)
http://www.dingge.com/forum/dispbbs.asp?boardID=43&ID=6972&page=1
9 #define和typedef的区别
1) #define是预处理指令,在编译预处理时进行简单的替换,不作正确性检查,不关含义是否正确照样带入,只有在编译已被展开的源程序时才会发现可能的错误并报错。例如:
#define PI 3.1415926
程序中的:area=PI*r*r 会替换为3.1415926*r*r
如果你把#define语句中的数字9 写成字母g 预处理也照样带入。
2)typedef是在编译时处理的。它在自己的作用域内给一个已经存在的类型一个别名,但是You cannot use the typedef specifier inside a function definition。
3)typedef int * int_ptr;
与
#define int_ptr int *
作用都是用int_ptr代表 int * ,但是二者不同,正如前面所说,#define在预处理 时进行简单的替换,而typedef不是简单替换 ,而是采用如同定义变量的方法那样来声明一种类型。也就是说;
//refer to (xzgyb(老达摩))
#define int_ptr int *
int_ptr a, b; //相当于int * a, b; 只是简单的宏替换
typedef int*int_ptr;
int_ptr a, b; //a, b 都为指向int的指针,typedef为int* 引入了一个新的助记符
这也说明了为什么下面观点成立
//QunKangLi(维护成本与程序员的创造力的平方成正比)
typedef int * pint ;
#define PINT int *
那么:
const pint p ;//p不可更改,但p指向的内容可更改
const PINT p ;//p可更改,但是p指向的内容不可更改。
pint是一种指针类型 const pint p 就是把指针给锁住了 p不可更改
而const PINT p 是const int * p 锁的是指针p所指的对象。
4)也许您已经注意到#define不是语句不要在行末加分号,否则会连分号一块置换。
6 INT_PTR
MFC中定义INT_PTR之类的用意是什么,不是问怎么定义的,是问为什么要搞这个东西出来?
INT_PTR是特殊定义的类型
在_W64(即__w64)中: int --> INT_PTR
是为了解决32位与64位编译器的兼容性而设置的关键字
17
sizeof是用来计算变量所占的内存字节数
7 set 的用法stringsstream iostreamfstream 用法
相关内容:http://blog.youkuaiyun.com/xlm289348/article/details/7837829
http://blog.youkuaiyun.com/xlm289348/article/details/7837822
fstream用法 STL //输入输出文件流类
fstream的使用方法
ofstream(输出文件流)是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;
在C++中,有一个stream这个类,所有的I/O都以这个“流”类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符:
1、插入器(<<)
向流输出数据。比如说系统有一个默认的标准输出流(cout),一般情况下就是指的显示器,所以,cout<<"WriteStdout"<<’\n’;就表示把字符串"WriteStdout"和换行字符(’\n’)输出到标准输出流。
2、析取器(>>)
从流中输入数据。比如说系统有一个默认的标准输入流(cin),一般情况下就是指的键盘,所以,cin>>x;就表示从标准输入流中读取一个指定类型(即变量x的类型)的数据。
在C++中,对文件的操作是通过stream的子类fstream(filestream)来实现的,所以,要用这种方式操作文件,就必须加入头文件fstream。下面就把此类的文件操作过程一一道来。
一、打开文件
在fstream类中,有一个成员函数open(),就是用来打开文件的,其原型是:
void open(const char* filename,int mode,int access);
参数:
filename: 要打开的文件名
mode: 要打开文件的方式
access: 打开文件的属性
打开文件的方式在类ios(是所有流式I/O类的基类)中定义,常用的值如下:
ios::app: 以追加的方式打开文件
ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性
ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文
ios::in: 文件以输入方式打开(文件数据输入到内存)
ios::out: 文件以输出方式打开(内存数据输出到文件)
ios::nocreate:不建立文件,所以文件不存在时打开失败
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
ios::trunc: 如果文件存在,把文件长度设为0
可以用“或”把以上属性连接起来,如ios::out|ios::binary
打开文件的属性取值是:
0:普通文件,打开访问
1:只读文件
2:隐含文件
4:系统文件
可以用“或”或者“+”把以上属性连接起来,如3或1|2就是以只读和隐含属性打开文件。
例如:以二进制输入方式打开文件c:\config.sys
fstream file1;
file1.open("c:\\config.sys",ios::binary|ios::in,0);
如果open函数只有文件名一个参数,则是以读/写普通文件打开,即:
file1.open("c:\\config.sys"); <=>file1.open("c:\\config.sys",ios::in|ios::out,0);
另外,fstream还有和open()一样的构造函数,对于上例,在定义的时侯就可以打开文件了:
fstream file1("c:\\config.sys");
特别提出的是,fstream有两个子类:ifstream(inputfile stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件。ifstreamfile2("c:\\pdos.def");//以输入方式打开文件
ofstream file3("c:\\x.123");//以输出方式打开文件
所以,在实际应用中,根据需要的不同,选择不同的类来定义:如果想以输入方式打开,就用ifstream来定义;如果想以输出方式打开,就用ofstream来定义;如果想以输入/输出方式来打开,就用fstream来定义。
二、关闭文件
打开的文件使用完成后一定要关闭,fstream提供了成员函数close()来完成此操作,如:file1.close();就把file1相连的文件关闭。
三、读写文件
读写文件分为文本文件和二进制文件的读取,对于文本文件的读取比较简单,用插入器和析取器就可以了;而对于二进制的读取就要复杂些,下要就详细的介绍这两种方式
1、文本文件的读写
文本文件的读写很简单:用插入器(<<)向文件输出;用析取器(>>)从文件输入。假设file1是以输入方式打开,file2以输出打开。示例如下:
file2<<"ILove You";//向文件写入字符串"ILove You"
inti;
file1>>i;//从文件输入一个整数值。
这种方式还有一种简单的格式化能力,比如可以指定输出为16进制等等,具体的格式有以下一些
操纵符功能输入/输出
dec 格式化为十进制数值数据输入和输出
endl 输出一个换行符并刷新此流输出
ends 输出一个空字符输出
hex 格式化为十六进制数值数据输入和输出
oct 格式化为八进制数值数据输入和输出
setpxecision(int p) 设置浮点数的精度位数输出
比如要把123当作十六进制输出:file1<<hex<<123;要把3.1415926以5位精度输出:file1<<setpxecision(5)<<3.1415926。
2、二进制文件的读写
①put()
put()函数向流写入一个字符,其原型是ofstream&put(char ch),使用也比较简单,如file1.put(’c’);就是向流写一个字符’c’。
②get()
get()函数比较灵活,有3种常用的重载形式:
一种就是和put()对应的形式:ifstream&get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。
另一种重载形式的原型是:int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。
还有一种形式的原型是:ifstream&get(char *buf,int num,char delim=’\n’);这种形式把字符读入由 buf 指向的数组,直到读入了num 个字符或遇到了由delim 指定的字符,如果没使用delim 这个参数,将使用缺省值换行符’\n’。例如:
file2.get(str1,127,’A’);//从文件中读取字符到字符串str1,当遇到字符’A’或读取了127个字符时终止。
③读写数据块
要读写二进制数据块,使用成员函数read()和write()成员函数,它们原型如下:read(unsignedchar *buf,int num);
write(constunsigned char *buf,int num);
read()从文件中读取num 个字符到buf 指向的缓存中,如果在还未读入num 个字符时就到了文件尾,可以用成员函数int gcount();来取得实际读取的字符数;而 write() 从buf指向的缓存写num 个字符到文件中,值得注意的是缓存的类型是unsigned char *,有时可能需要类型转换。
例:
unsignedchar str1[]="I Love You";
intn[5];
ifstreamin("xxx.xxx");
ofstreamout("yyy.yyy");
out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中
in.read((unsignedchar*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换
in.close();out.close();
四、检测EOF
成员函数eof()用来检测是否到达文件尾,如果到达文件尾返回非0值,否则返回0。原型是inteof();
例: if(in.eof())ShowMessage("已经到达文件尾!");
五、文件定位
和C的文件操作方式不同的是,C++I/O系统管理两个与一个文件相联系的指针。一个是读指针,它说明输入操作在文件中的位置;另一个是写指针,它下次写操作的位置。每次执行输入或输出时,相应的指针自动变化。所以,C++的文件定位分为读位置和写位置的定位,对应的成员函数是seekg()和seekp()。seekg()是设置读位置,seekp是设置写位置。它们最通用的形式如下:
istream&seekg(streamoff offset,seek_dir origin);
ostream&seekp(streamoff offset,seek_dir origin);
streamoff定义于iostream.h 中,定义有偏移量 offset 所能取得的最大值,seek_dir表示移动的基准位置,是一个有以下值的枚举:
ios::beg: 文件开头
ios::cur: 文件当前位置
ios::end: 文件结尾
这两个函数一般用于二进制文件,因为文本文件会因为系统对字符的解释而可能与预想的值不同。例:
file1.seekg(1234,ios::cur);//把文件的读指针从当前位置向后移1234个字节
file2.seekp(1234,ios::beg);//把文件的写指针从文件开头向后移1234个字节
fstream f;
f.open("1.txt", ios::in | ios::binary);
if (!f.is_open()) // 检查文件是否成功打开
cout << "cannot open file." <<endl;
ios::in与ios::bianry均为int型,定义文件打开的方式。
ios::in -- 打开文件用于读。
ios::out -- 打开文件用于写,如果文件不存在,则新建一个;存在则清空其内容。
ios::binary -- 以二进制bit流方式进行读写,默认是ios::text,但最好指定这种读写方式,即使要读写的是文本。因为在ios::text模式下,在写入时’\n’字符将转换成两个字符:回车+换行(HEX:0D 0A) 写入,读入时作逆转换,这容易引起不必要的麻烦。ios::app-- 打开文件在文件尾进行写入,即使使用了seekp改变了写入位置,仍将在文件尾写入。
ios::ate -- 打开文件在文件尾进行写入,但seekp有效。
读写位置的改变
f.seekg(0, ios::beg); // 改变读入位置 g meanGet
f.seekp(0, ios::end); // 改变写入位置 p meanPut
第一个参数是偏移量offset(long),第二个参数是offset相对的位置,三个值:
ios::beg -- 文件头 ios::end -- 文件尾 ios::cur-- 当前位置
文件读写
char s[50];
f.read(s, 49);
s[50] = ’\0’; // 注意要自己加上字符串结束符
char *s = "hello";
f.write(s, strlen(s));
补充 记得读写完成后用f.close()关闭文件。
例子 下面的程序用于删除带有行号的源程序中的行号。
#include <iostream>
#include <fstream>
using namespace std;
//定义要删除的行号格式,下面定义的是型如:#0001 的行号
const int LINE_NUM_LENGTH = 5;
const char LINE_NUM_START = ’#’;
int main(int argc, char *argv[])
{
fstream f;
char *s = NULL;
int n;
for (int i = 1; i < argc; i++) {
cout << "Processing file " <<argv[i] << "......";
f.open(argv[i], ios::in | ios::binary);
if (!f.is_open()){
cout << "CANNOTOPEN"<< endl;
continue;
}
f.seekg(0, ios::end);
n = f.tellg(); // 文件大小
s = new char[n+1];
f.seekg(0, ios::beg);
f.read(s, n);
s[n] = ’\0’;
f.close();
// 采用一种简单的判断,遇到LINE_NUM_START后接一个数字,
// 则认为它是一个行号.
for (int j = 0; j < n; j++) {
if (s[j] == LINE_NUM_START&& (s[j+1]>= ’0’ && s[j+1] <= ’9’)) {
for(int k = j; k < j + LINE_NUM_LENGTH; k++)
s[k]= ’ ’;
}
}
f.open(argv[i], ios::out | ios::binary);
if (!f.is_open()) {
cout << "CANNOTOPEN" << endl;
delete[] s;
continue;
}
f.write(s, n);
f.close();
cout << "OK" << endl;
delete[] s;
}
return 0;
}
8 sizeof与strlen的用法
http://blog.youkuaiyun.com/rsp19801226/article/details/3095157
解析C/C++语言中的sizeof
一、sizeof的概念
sizeof是C/C++中的一个操作符(operator),简单的说其作用就是返回一个对象或者类型所占的内存字节数。
sizeof有三种语法形式,如下:
1)sizeof( object ); // sizeof( 对象 );
2)sizeof( type_name ); // sizeof(类型 );
3)sizeof object; // sizeof 对象;
所以,
int i;
sizeof(i ); // ok
sizeofi; // ok
sizeof(int ); // ok
sizeofint; // error
既然写法3可以用写法1代替,为求形式统一以及减少我们大脑的负担,第3种写法,忘掉它吧!实际上,sizeof计算对象的大小也是转换成对对象类型的计算,也就是说,同种类型的不同对象其sizeof值都是一致的。这里,对象可以进一步延伸至表达式,即sizeof可以对一个表达式求值,编译器根据表达式的最终结果类型来确定大小,一般不会对表达式进行计算。如:
sizeof(2 ); // 2的类型为int,所以等价于 sizeof( int );
sizeof( 2 + 3.14 ); // 3.14的类型为double,2也会被提升成double类型,所以等价于 sizeof(double );
sizeof是C语言的一种单目操作符,如C语言的其他操作符++、--等。它并不是函数。sizeof操作符以字节形式给出了其操作数的存储大小。操作数可以是一个表达式或括在括号内的类型名。操作数的存储大小由操作数的类型决定。
二、sizeof的使用方法
1、用于数据类型
sizeof使用形式:sizeof(type)
数据类型必须用括号括住。如sizeof(int)。
2、用于变量
sizeof使用形式:sizeof(var_name)或sizeof var_name
变量名可以不用括号括住。如sizeof (var_name),sizeof var_name等都是正确形式。带括号的用法更普遍,大多数程序员采用这种形式。
注意:sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。
如sizeof(max)若此时变量max定义为intmax(),sizeof(char_v) 若此时char_v定义为char char_v [MAX]且MAX未知,sizeof(void)都不是正确形式。
三、sizeof的结果
sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。
1、若操作数具有类型char、unsigned char或signed char,其结果等于1。
ANSI C正式规定字符类型为1字节。
2、int(4)、unsigned int(4)、short int(2)、unsignedshort(2) 、long int(4) 、unsigned long (4)、float(4)、double(8)、long double(8)类型的sizeof 在ANSI C中没有具体规定,大小依赖于实现括号内为sizeof的结果。
3、当操作数是指针时,sizeof依赖于编译器。例如Microsoft C/C++7.0中,near类指针字节数为2,far、huge类指针字节数为4。一般Unix的指针字节数为4,一般来说指针字节数为4。
例1:
int *p;
int a[5];
p = a;
sizeof(p)的结果是4。
例2:
const char*pstars[]={"aa","bb","cc","dd"};
const int starCount=size ofpstars/sizeof pstars[0];
starCount是指针数组pstars中的元素个数4。
因为pstars是一个常指针数组,const代表指针中的数据不能修改,即不能使用诸如*pstars[0] = 'c';之类,会有编译错误的。
先放下const不谈,pstars的数组成员是4个指针,所以其占用的空间是4个指针所占用的空间即4*4 = 16,而pstars[0]是该数组的一个元素,即一个指针,所占空间即为4个字节。所以最后计算结果为4。
4、当操作数具有数组类型时,其结果是数组的总字节数。
例如:inta[12];sizeof(a)的结果是12 * 4 =48。
5、联合类型操作数的sizeof是其最大字节成员的字节数。结构类型操作数的sizeof是这种类型对象的总字节数,包括任何垫补在内。
让我们看如下结构:
struct{char b; double x;} a;
vc6.0结果为16。
这是因为编译器在考虑对齐问题时,在结构中插入空位以控制各成员对象的地址对齐。如double类型的结构成员x要放在被8整除的地址。可以通过#pragma pack(n)改变字节对齐。
例如:
struct mystruct1{
char a; //1
int b; //4
short c; //2
long d; //4
double e; //8
};
默认的结构体的sizeof结果是24。
#pragma pack(2)
struct mystruct1{
char a; //1
int b; //4
short c; //2
long d; //4
double e; //8
};
此时结果为20。
我的推论:
默认时以最大字节作为存储单位,即8字节,而对齐方式则以两两之间的最大字节对齐,比如char与int以4字节对齐,占用了一个8字节空间,short重新开始一个8字节空间,short与long以4字节对齐,再结合成一个8字节空间,同时double单独占用一个8字节空间,所以最后总空间为24字节。
改变对齐方式为2字节时,则char以2字节后接int的2个2字节,再接short的2字节,再接long的2个2字节最后接double的4个2字节,此时计算总数为2字节 * (1+2+1+2+4)=20字节。
注意:#pragma pack()可以还原为默认对齐方式,而要改变其对齐方式,#pragmapack(n)必须放在使用之前。也可以使用
#pragmapack(push) //保存对齐状态
#pragmapack(pop) //恢复对齐状态
这一对来进行对齐方式的改变。
C++中类也是类似结构体的sizeof的计算方式,计算类对象中数据成员所占用的空间,不过static对象不计算在内。
例如:
class A{
char b;
static double x;
public:
void count(int *aa);
};
此时sizeof(A)的结果是1。
6、如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。
例如:
void a(int *c)
{
printf("%d/n",sizeof(c));
}
void a(int c[13])
{
printf("%d/n",sizeof(c));
}
打印的都是4。
四、sizeof与其他操作符的关系
sizeof的优先级为2级,比/、%等3级运算符优先级高。它可以与其他操作符一起组成表达式。如i*sizeof(int);其中i为int类型变量。
五、sizeof的主要用途
1、sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信。例如:
void*malloc(size_tsize),
size_tfread(void * ptr,size_t size,size_t nmemb,FILE * stream)。
2、sizeof的另一个的主要用途是计算数组中元素的个数。例如:
void* memset(void *s,int c,sizeof(s))。
六、建议
由于操作数的字节数在实现时可能出现变化,建议在涉及到操作数字节大小时用sizeof来代替常量计算。
解析C/C++语言中的strlen与sizeof的区别
1.从功能定义上,strlen函数,用来求字符串的长度,sizeof函数是用来求指定变量或变量类型等所占用内存的大小;
2.sizeof是运算符,而strlen是C库函数strlen只能用char*做参数,且以'/0'结尾的;
对于静态数组处理:
charstr[20]="0123456789";
strlen(str)=10;//表示数组中字符串的长度
sizeof(str)=20;//表示数组变量分配的长度
对于指针处理:
char*str="0123456789";
strlen(str)=10;//表示字符串的长度
sizeof(str)=4;//表示指针变量的所占内存大小
sizeof(*str)=1;//表示'0'这个字符变量的所占内存大小
9MSDN 的使用方法:
TCHAR.H routine 既可以是多字节 ,也可以是双字节UNICODE;
_UNICODE & _MBCS not defined 对应的是多字节;
_UNICODE defined 对应的是双字节,UNICODE;
Generic-Text Routine Mappings // Generic-Text常规映射
TCHAR.H routine | _UNICODE & _MBCS not defined | _MBCS defined | _UNICODE defined |
_tcslen | strlen | strlen | wcslen |
_tcsclen | strlen | _mbslen | wcslen |
_tcsclen_l | strlen_l | _mbslen_l | wcslen_l |
10 函数名: atof
功 能: 把字符串转换成浮点数
名字来源:array to floating point numbers 的缩写
用 法: double atof(constchar *nptr);
程序例:
#include <stdlib.h>
#include <stdio.h>
int main()
{
float f;
char *str = "12345.67";
f = atof(str);
printf("string = %s float = %f\n", str, f);
return 0;
}
11函数名: itoa
功 能: 把一整数转换为字符串
itoa(i,num,10);
i 需要转换成字符的数字
num 转换后保存字符的变量
10 转换数字的基数(进制)10就是说按照10进制转换数字。还可以是2,8,16等等你喜欢的进制类型;
12 GetPrivateProfileString函数的使用方法
Ini文件说明:
[节名] '[]中的节名对应此API的第一参数
Name=内容 'Nmae对应此API的第二参数
API的第三参数是没有取到匹配内容时返回的字符串;
API的第四参数是要返回的字符串;
API的第五参数是字符串缓冲的长度,一般255;
API的第六参数是INI文件的路径。
GetPrivateProfileString("节名","Name","没有获得匹配",s,len(s),你那ini的路径);
13 比较两个字符是不是相等
C++中对于数字类型的数据我们可以直接使用"=="即可比较是否相等,但是对于字符串的比较并不适用。我们可以利用以下的两个函数来比较两个字符串是否相等。
(1)strcmp
这是用于ANSI标准字符串的函数(如string和char *),此函数接受两个字符串缓冲区做为参数,如果两个字符串是相同的则返回零。否则若第一个传入的字符串的值大于第二个字符串返回值将会大于零,若传入的第一个字符串的值小于第二个字符串返回值将小于零。
char *ch="翔翔糖糖";
if(strcmp(ch,"翔翔糖糖")==0)
{
//字符串相等
}
else
{
//字符串不相等
}
(2)wcscmp
这个函数是strcmp所对应的Unicode系列的函数,它的使用方法和strcmp相同,它用来比较两个Unicode字符串是否相等(如wstring和wchar_t *)。
wchar_t*ch=L"翔翔糖糖";
if(wcscmp(ch,L"翔翔糖糖")==0)
{
//字符串相等
}
else
{
//字符串不相等
}
注:以上所介绍的比较字符串是否相等的函数对于英文来说是要区分大小写的,即使字母都相同但是大小写不同,函数也会认为这两个字符串是不同的。
14 switch-case语句用法
if语句处理两个分支,处理多个分支时需使用if-else-if结构,但如果分支较多,则嵌套的if语句层就越多,程序不但庞大而且理解也比较困难.因此,C语言又提供了一个专门用于处理多分支结构的条件选择语句,称为switch语句,又称开关语句.使用switch语句直接处理多个分支(当然包括两个分支).其一般形式为:
switch(表达式)
{
case 常量表达式1:
语句1;
break;
case 常量表达式2:
语句2;
break;
……
case 常量表达式n:
语句n;
break;
default:
语句n+1;
break;
}
switch语句的执行流程是:首先计算switch后面圆括号中表达式的值,然后用此值依次与各个case的常量表达式比较,若圆括号中表达式的值与某个case后面的常量表达式的值相等,就执行此case后面的语句,执行后遇break语句就退出switch语句;若圆括号中表达式的值与所有case后面的常量表达式都不等,则执行default后面的语句n+1,然后退出switch语句。
15 #define 指令
该指令 有三种用法:
第一种是定义标识,标识有效范围为整个程序,形如#define XXX,常与#if配合使用;
第二种是定义常数,如#define max 100,则max代表100(这种情况下使用const定义常数更好,因为:const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误);
第三种是定义"函数",如#define get_max(a, b) ((a)>(b)?(a):(b)) 则以后使用get_max(x,y)就可以得到x和y中较大的数(这种方法存在一些弊病,如get_max(a++, b)时,a++会被执行多少次取决于a和b的大小!所以建议还是用内联函数而不是这种方法提高速度。虽然有这样的弊病,但这种方法的确非常灵活,因为a和b可以是各种数据类型。)。
16 预处理功能中三种(宏定义,文件包含和条件编译)
#ifndefx //先测试x是否被宏定义过
#definex
程序段1//如果x没有被宏定义过,定义x,并编译程序段1
#endif
程序段2 //如果x已经定义过了则编译程序段2的语句,“忽视”程序段1。
#endif
预编译处理是指在编译系统对文件进行编译---词法分析、语法分析、代码生成及优化之前,对一些特殊的编译语句先进行处理,然后将处理结果与源程序一起编译,生成目标文件。
预编译处理语句都是以#开头,其结尾不带分号,与普通程序语句相区别。
#endif用于结束条件编译,编译时与前面最近的#if、#ifdef或#ifndef作为一对,经常一起使用,编译两者之间的部分程序段。
#undef
#undef 是在后面取消以前定义的宏定义
该指令的形式为:
#undef 标识符
其中,标识符是一个宏名称。如果标识符当前没有被定义成一个宏名称,那么就会忽略该指令。
17文件包含命令格式如下:
#include <文件名>
或者
#include "文件名”
其中,include是关键字,文件名是指被包含的文件全名。在前面我们已多次用此命令包含过库函数的头文件。例如:"#include "stdio.h""。
18
extern"C"//如果定义了C++编译器,那么声明为C链接方式;
19 vc++ 中HINSTANCE和HANDLE(柄)的区别是什么?
HINSTANCE(标识一个应用程序模块的一个实例;实例句柄)
HINSTANCE对应的资源是instance.句柄实际上是一个无符号长整数。但它是“句柄型”,所以你不能把它当成真的无符号长整数,拿来派别的用处,例如,不能拿来做四则运算。
HANDLE:是Windows用来表示对象的(不是C++的对象),HWND是其中一种,HWND是HANDLE,但HANDLE不只是HWND。
HANDLE(句柄)是windows操作系统中的一个概念。在window程序中,有各种各样的资源(窗口、图标、光标等),系统在创建这些资源时会为它们分配内存,并返回标示这些资源的标示号,即句柄。句柄指的是一个核心对象在某一个进程中的唯一索引,而不是指针。由于地址空间的限制,句柄所标识的内容对进程是不可见的,只能由操作系统通过进程句柄列表来进行维护。句柄列表: 每个进程都要创建一个句柄列表,这些句柄指向各种系统资源,比如信号量,线程,和文件等,进程中的所有线程都可以访问这些资源。
其实我们编程时输出一下句柄的值就可以发现这些值往往非常小(<100)。由此就可以看出句柄的性质了。
无效的返回值为:INVALID_HANDLE_VALUE
编程时可作调试用:
例如
voidmain()
{
charch[20]="Test.dsw";
HANDLEhandle;
LPWIN32_FIND_DATAfd;
handle= FindFirstFile(ch, fd);
if(handle != INVALID_HANDLE_VALUE)
cout<<"ok"<<endl;
else
cout<<"no"<<endl;
}
在WinDef.h有这么一句:typedef HANDLE HINSTANCE;
数据上两者是一样的,本质上没什么区别。
HANDLE是用来标记资源的,也就是handle to an object。
HINSTANCE是Handle to an instance, 是HANDLE的一种特殊情况,常用来标记
App实例。
用HINSTANCE而不是HANDLE只是给用者一种说明的作用。
20 typedef的用法
http://www.cnblogs.com/cxun/archive/2007/04/28/731455.html
用途一:
定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如:
char* pa,pb; // 这多数不符合我们的意图,它只声明了一个指向字符变量的指针,
// 和一个字符变量;
以下则可行:
typedef char*PCHAR;
PCHAR pa,pb;
typedef (类型定义);
用途二:
用在旧的C代码中,帮助struct。以前的代码中,声明struct新对象时,必须要带上struct,即形式为: struct 结构名对象名,如:
struct tagPOINT1
{
intx;
inty;
};
struct tagPOINT1p1;
而在C++中,则可以直接写:结构名对象名,即:tagPOINT1 p1;
typedefstructtagPOINT
{
intx;
inty;
}POINT;
POINT p1; // 这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时候
或许,在C++中,typedef的这种用途二不是很大,但是理解了它,对掌握以前的旧代码还是有帮助的,毕竟我们在项目中有可能会遇到较早些年代遗留下来的代码。
用途三:
用typedef来定义与平台无关的类型。
比如定义一个叫 REAL 的浮点类型,在目标平台一上,让它表示最高精度的类型为:
typedef longdouble REAL;
在不支持 longdouble 的平台二上,改为:
typedef doubleREAL;
在连 double 都不支持的平台三上,改为:
typedef floatREAL;
也就是说,当跨平台时,只要改下 typedef 本身就行,不用对其他源码做任何修改。
标准库就广泛使用了这个技巧,比如size_t。
另外,因为typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健。
用途四:
为复杂的声明定义一个新的简单的别名。方法是:在原来的声明里逐步用别名替换一部分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化版。举例:
原声明:void (*b[10])(void (*)());
变量名为b,先替换右边部分括号里的,pFunParam为别名一:
typedef void(*pFunParam)();
再替换左边的变量b,pFunx为别名二:
typedef void(*pFunx)(pFunParam);
原声明的最简化版:
pFunx b[10];
原声明:doube(*)()(*e)[9];
变量名为e,先替换左边部分,pFuny为别名一:
typedefdouble(*pFuny)();
再替换右边的变量e,pFunParamy为别名二
typedef pFuny(*pFunParamy)[9];
原声明的最简化版:
pFunParamy e;
理解复杂声明可用的“右左法则”:从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。举例:
int (*func)(int*p);
首先找到变量名func,外面有一对圆括号,而且左边是一个*号,这说明func是一个指针;然后跳出这个圆括号,先看右边,又遇到圆括号,这说明(*func)是一个函数,所以func是一个指向这类函数的指针,即函数指针,这类函数具有int*类型的形参,返回值类型是int。
int (*func[5])(int*);
func右边是一个[]运算符,说明func是具有5个元素的数组;func的左边有一个*,说明func的元素是指针(注意这里的*不是修饰func,而是修饰func[5]的,原因是[]运算符优先级比*高,func先跟[]结合)。跳出这个括号,看右边,又遇到圆括号,说明func数组的元素是函数类型的指针,它指向的函数具有int*类型的形参,返回值类型为int。
21 C/C++中typedef struct和struct的用法
http://www.iteye.com/topic/143629
1. 由于对typedef理解不够,因此从网上摘录了一些资料,整理如下:
2. C/C++中typedef struct和struct的用法
3. struct _x1 { ...}x1; 和 typedef struct _x2{ ...} x2; 有什么不同?
4. 其实, 前者是定义了类_x1和_x1的对象实例x1, 后者是定义了类_x2和_x2的类别名x2 ,
5. 所以它们在使用过程中是有取别的.请看实例1.
6. [知识点]
7. 结构也是一种数据类型, 可以使用结构变量, 因此, 象其它 类型的变量一样, 在使用结构变量时要先对其定义。
8. 定义结构变量的一般格式为:
9. struct 结构名
10. {
类型 变量名;
11. 类型 变量名;
12. ...
13. } 结构变量;
14. 结构名是结构的标识符不是变量名。
15. 另一种常用格式为:
16. typedef struct 结构名
17. {
18. 类型 变量名;
19. 类型 变量名;
20. ...
21.
22. } 结构别名;
23. 另外注意: 在C中,struct不能包含函数。在C++中,对struct进行了扩展,可以包含函数。
24. ======================================================================
25.
26. 实例1: struct.cpp
27.
28. #include <iostream>
29.
30. using namespace std;
31.
32. typedef struct _point{
33.
34. int x;
35.
36. int y;
37.
38. }point; //定义类,给类一个别名
39. struct _hello{
40.
41. int x,y;
42.
43. } hello; //同时定义类和对象
44. int main()
45.
46. {
47.
48. point pt1;
49.
50. pt1.x = 2;
51.
52. pt1.y = 5;
53.
54. cout<< "ptpt1.x=" << pt1.x << "pt.y=" <<pt1.y <<endl;
55.
56. //hello pt2;
57.
58. //pt2.x = 8;
59.
60. //pt2.y =10;
61.
62. //cout<<"pt2pt2.x="<< pt2.x <<"pt2.y="<<pt2.y <<endl;
63.
64. //上面的hello pt2;这一行编译将不能通过. 为什么?
65.
66. //因为hello是被定义了的对象实例了.
67.
68. //正确做法如下: 用hello.x和hello.y
69.
70. hello.x = 8;
71.
72. hello.y = 10;
73.
74. cout<< "hellohello.x=" << hello.x << "hello.y=" <<hello.y <<endl;
75.
76. return 0;
77.
78. }
。。。。。。。
22 LRESULT
LRESULT是一个数据类型,
MSDN:32-bit value returned from a window procedure or callback function
指的是从窗口程序或者回调函数返回的32位值。
在winnt.h中typedeflong LONG;
在windef.h中typedefLONG LRESULT;
所以LRESULT就是longresult,也就是长整形
之所以取名类LRESULT,是因为L即long
result表示结果,说明这个函数的返回值是某个结果。
23 #pragma comment
#pragma comment( comment-type,["commentstring"] )
comment-type是一个预定义的标识符,指定注释的类型,应该是compiler,exestr,lib,linker之一。
commentstring是一个提供为comment-type提供附加信息的字符串。
Remarks:
1、compiler:放置编译器的版本或者名字到一个对象文件,该选项是被linker忽略的。
2、exestr:在以后的版本将被取消。
3、lib:放置一个库搜索记录到对象文件中,这个类型应该是和commentstring(指定你要Liner搜索的lib的名称和路径)
这个库的名字放在Object文件的默认库搜索记录的后面,linker搜索这个这个库就像你在命令行输入这个命令一样。你可以
在一个源文件中设置多个库记录,它们在object文件中的顺序和在源文件中的顺序一样。如果默认库和附加库的次序是需要
区别的,使用Z编译开关是防止默认库放到object模块。
4、linker:指定一个连接选项,这样就不用在命令行输入或者在开发环境中设置了。
只有下面的linker选项能被传给Linker.
24 ofstreamifstream 文件操作
输入和输出格式:
输出到磁盘 ofsteam识别字(“文件名”)
从磁盘读文件 ifsteam识别字("文件名“)
例如:
ofstreamoutfile("data.txt"); //写入到磁盘的data.txt中
25 SYSTEMTIME
在Win32程序汇编中有SYSTEMTIME类数据结构。SYSTEMTIME结构定义如下:
SYSTEMTIMESTRUCT
{
WORDwYear ; 年
WORDwMonth ;月
WORDwDayOfWeek ;星期,0=星期日,1=星期一...
WORDwDay ;日
WORDwHour ;时
WORDwMinute ;分
WORDwSecond ;秒
WORDwMilliseconds ;毫秒
}SYSTEMTIME ENDS
结构中的字段全为word类型,而Win32程序中用的往往是dword型变量,所以在使用这些数据之前往往要先把它们转换为dword类型,用movzx指令就可以实现。
在SYSTEMTIME数据结构里,日期和时间都被编码了.月份是从1月开始的(一月份就是1月)。周日是从0开始的(星期天是0).wDay是在当前月份下的日期,也是从1开始的。
与获取系统时间的函数相对应,可以用下面的两个函数设置系统时间:
invokeSetLocalTime,lpSystemTime;获取本地时间
invoke SetSystemTime,lpSystemTime;获取格林威治标准时间
26 GetLocalTime
WindowsAPI 函数
函数功能:该函数用来获取当地的当前系统日期和时间。
函数原型:
VOIDGetLocalTime(
LPSYSTEMTIMElpSystemTime //address of system times structure系统时间结构的地址);
参数说明:
lpSystemTime:指向一个用户自定义包含日期和时间信息的类型为SYSTEMTIME 的变量,该变量用来保存函数获取的时间信息。
此函数会把获取的系统时间信息存储到SYSTEMTIME结构体里边
typedefstruct _SYSTEMTIME
{
WORDwYear;//年
WORDwMonth;//月
WORDwDayOfWeek;//星期,0为星期日,1为星期一,2为星期二……
WORDwDay;//日
WORDwHour;//时
WORDwMinute;//分
WORDwSecond;//秒
WORDwMilliseconds;//毫秒
}SYSTEMTIME,*PSYSTEMTIME;
27 MSG结构体
Contains message information from a thread's message queue:包含消息信息从一个线程的消息队列。
在Windows程序中,消息是由MSG结构体来表示的。MSG结构体的定义如下(参见MSDN):
typedefstruct tagMSG {
HWNDhwnd;
UINTmessage;
WPARAMwParam;
LPARAMlParam;
DWORDtime;
POINTpt;
}MSG;
该结构体中各成员变量的含义如下:
第一个成员变量hwnd表示消息所属的窗口。我们通常开发的程序都是窗口应用程序,一个消息一般都是与某个窗口相关联的。例如,在某个活动窗口中按下鼠标左键,产生的按键消息就是发给该窗口的。在Windows程序中,用HWND类型的变量来标识窗口。
第二个成员变量message指定了消息的标识符。在Windows中,消息是由一个数值来表示的,不同的消息对应不同的数值。但是由于数值不便于记忆,所以Windows将消息对应的数值定义为WM_XXX宏(WM是Window Message的缩写)的形式,XXX对应某种消息的英文拼写的大写形式。例如,鼠标左键按下消息是WM_LBUTTONDOWN,键盘按下消息是WM_KEYDOWN,字符消息是WM_CHAR,等等。在程序中我们通常都是以WM_XXX宏的形式来使用消息的。
提示:如果想知道WM_XXX消息对应的具体数值,可以在Visual C++开发环境中选中WM_XXX,然后单击鼠标右键,在弹出菜单中选择goto definition,即可看到该宏的具体定义。跟踪或查看某个变量的定义,都可以使用这个方法。
第三、第四个成员变量wParam和lParam,用于指定消息的附加信息。例如,当我们收到一个字符消息的时候,message成员变量的值就是WM_CHAR,但用户到底输入的是什么字符,那么就由wParam和lParam来说明。wParam、lParam表示的信息随消息的不同而不同。如果想知道这两个成员变量具体表示的信息,可以在MSDN中关于某个具体消息的说明文档查看到。读者可以在VC++的开发环境中通过goto definition查看一下WPARAM和LPARAM这两种类型的定义,可以发现这两种类型实际上就是unsigned int和long。
最后两个变量分别表示消息投递到消息队列中的时间和鼠标的当前位置。
28GetMessage
函数GetMessage是从调用线程的消息队列里取得一个消息并将其放于指定的结构。此函数可取得与指定窗口联系的消息和由PostThreadMesssge寄送的线程消息。此函数接收一定范围的消息值。GetMessage不接收属于其他线程或应用程序的消息。获取消息成功后,线程将从消息队列中删除该消息。函数会一直等待直到有消息到来才有返回值。
函数声明:
BOOL GetMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax)
参数:
lpMsg:指向MSG结构的指针,该结构从线程的消息队列里接收消息信息。
hWnd:取得其消息的窗口的句柄。当其值取NULL时,GetMessage为任何属于调用线程的窗口检索消息,线程消息通过PostThreadMessage寄送给调用线程。
wMsgFilterMin:指定被检索的最小消息值的整数。
wMsgFilterMax:指定被检索的最大消息值的整数。
返回值:如果函数取得WM_QUIT之外的其他消息,返回非零值。如果函数取得WM_QUIT消息,返回值是零。如果出现了错误,返回值是-1。例如,当hWnd是无效的窗口句柄或lpMsg是无效的指针时。若想获得更多的错误信息,请调用GetLastError函数。
29 WM_CLOSE,WM_QUIT,WM_DESTROY区别?
WM_DESTROY 是关闭程序的
WM_CLOSE 是关闭窗口的
WM_QUIT 是关闭消息环的
以下说明程序是如何退出的: