string类find函数find_first_ofsubstr函数 动态载入DLL相关函数LoadLibrary函数GetProcAddress函数FreeLibrary函数 getopt函数判断文件的访问权限localtime函数SetConsoleCtrlHandler控制台处理函数inline函数CreateDirectory创建文件目录整形字符转换strtoul函数_ultoa函数 进程或线程相关函数SetPriorityClass获取当前进程或线程句柄或IDCreateToolhelp32Snapshot进程快照获取进程中的线程或线程枚举OpenThread打开线程SetThreadAffinityMask 指定线程的运行CPU 时间函数获取系统内存信息WSAStartup和WSACleanupInterlockedIncrement16和InterLockedDecrement
string类
find函数
四种函数原型:
(1)size_t find (const string& str, size_t pos = 0) const; //查找对象--string类对象(2)size_t find (const char* s, size_t pos = 0) const; //查找对象--字符串(3)size_t find (const char* s, size_t pos, size_t n) const; //查找对象--字符串的前n个字符(4)size_t find (char c, size_t pos = 0) const; //查找对象--字符
-rfind() 与之类似,只是从反向查找-返回值 :
找到返回 第一个字符的索引没找到返回 string::npos
#include <string> #include <iostream> using namespace std; int main() { string strFirst ( "abced" ),strSecond("abc abc abd def"); cout<<strFirst.find("a")<<endl;//输出结果为0,说明a当前的索引位置为0 //函数原型:size_type find_first_not_of( Char ch, size_type index = 0 ) const; //返回在字符串中首次不匹配 d 的首字符索引,从2开始。 cout<<strFirst.find_first_not_of ( "d" ,2)<<endl; //输出结果为 2cout<<strSecond.length()<<endl;//输出结果为15 cout<<strSecond.find_first_not_of("abc",4)<<endl; //输出结果为7 system("pause"); }
find_first_of
[函数原型]
size_type find_first_of( const basic_string &str, size_type pos= 0 ); size_type find_first_of( const char *str, size_type pos= 0 ); size_type find_first_of( const char *str, size_type pos, size_type num ); size_type find_first_of( char ch, size_type pos= 0 );
[说明]
查找在字符串中第一个与str中的某个字符匹配的字符,返回它的位置。搜索从index开始,如果没找到就返回string::npos ;
查找在字符串中第一个与str中的某个字符匹配的字符,返回它的位置。搜索从index开始,最多搜索num个字符。如果没找到就返回string::npos;
查找在字符串中第一个与ch匹配的字符,返回它的位置。搜索从index开始;
substr函数
原型:
string.substr(size_t startpos, size_tlength);
其中 startpos 是起始字符的序号,length 是[从 startpos 开始]取的字符串长度(包括startpos )。
如果要取得 str 中序号 m 到 n 之间(不包括n)的子字符串需要用str.substr(m, n-m);
示例代码:
#include<string>#include<iostream>using namespace std;main(){string s("12345asdf");string a=s.substr(0,4); //获得字符串s中 从第0位开始的长度为4的字符串cout<<a<<endl;}
输出结果:
1234
动态载入DLL相关函数
DLL是Dynamic Link Library的缩写,意为动态链接库。在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。
动态载入方式是指在编译之前并不知道将会调用哪些 DLL 函数, 完全是在运行过程中根据需要决定应调用哪些函数。
方法是:用 LoadLibrary 函数加载动态链接库到内存,用 GetProcAddress函数动态获得 DLL 函数的入口地址。当一个 DLL 文件用 LoadLibrary 显式加载后,在任何时刻均可以通过调用 FreeLibrary 函数显式地从内存中把它给卸载。
动态调用使用的 Windows API 函数主要有 3 个, 分别是 LoadLibrary、 GetProcAddress 和FreeLibrary。
实例代码:
#include <stdio.h> #include <stdlib.h> #include <windows.h> //假如CreateDll.dll这个dll中有一个函数Add(int a, int b); //定义一个函数指针 typedef int (*func_Add)(int a, int b); int main(int argc, char *argv[]) { int sum = 0; HMODULE h = NULL; func_Add func_Add_from_dll = NULL; //注意dll的路径,视自己的情况而定 h = LoadLibrary("..\\CreateDll\\CreateDll.dll"); if(NULL == h) { printf("LoadLibrary failed!\n"); return 0; } func_Add_from_dll = (func_Add)GetProcAddress(h, "Add"); if(NULL == func_Add_from_dll) { printf("GetProcAddress failed!\n"); return 0; } sum = (*func_Add_from_dll)(1, 2);printf("%d\n", sum); getchar(); return 0; }
LoadLibrary函数
原型:
HMODULE LoadLibrary(char * LibFileName)
[功能]:加载由参数 LibFileName 指定的 DLL 文件。
[返回值]:返回装载 DLL 库模块的实例句柄。
[说明]:参数 LibFileName 指定了要装载的 DLL 文件名,如果 LibFileName 没有包含一个路径,系统将按照:当前目录、Windows 目录、Windows 系统目录、包含当前任务可执行文件的目录、列在 PATH 环境变量中的目录等顺序查找文件。
如果函数操作成功,将返回装载 DLL 库模块的实例句柄,否则,将返回一个错误代码
注意:假如在应用程序中用 LoadLibrary 函数装入某一个 DLL 前, 其他应用程序已把该 DLL 装入内存中了,则系统将不再装入该 DLL 的另一个实例,而是使该 DLL 的“引用计数”加 1 。
GetProcAddress函数
原型:
func_pointer GetProcAddress(HMODULE h,char * func_name)
[功能]:返回参数 h指定的模块中(由LoadLibrary函数返回的指向DLL模块的参数),由参数 func_name指定的过程或函数的入口地址。
[说明]:参数 h包含被调用函数的 DLL 句柄,这个值由 LoadLibrary 返回, func_name是指向含有函数名的以 nil 结尾的字符串指针,或者可以是函数的次序值,但大多数情况下,用函数名是一种更稳妥的选择。
如果该函数执行成功,则返回 DLL 中由参数 func_name指定的过程或函数的入口地址,否则返回 nil 。
FreeLibrary函数
原型:
FreeLibrary(HMODULE h)
[说明]:将由参数 h指定的 DLL 文件从内存中卸载 1 次。h为 DLL 库的句柄。这个值由 LoadLibrary 返回。由于 DLL 在内存中只装载一次,因此调用 FreeLibrary 首先使 DLL 的引用计数减 1,如果计数减为 0 则卸载该 DLL。
注意:每调用一次 LoadLibrary 函数就应调用一次 FreeLibrary 函数,以保证不会有多余的库模块在应用程序结束后仍留在内存中,否则导致内存泄漏。
getopt函数
示例代码:
#include <stdio.h> #include <unistd.h> int main(int argc,char *argv[]) { int ch; opterr=0; while((ch=getopt(argc,argv,"a:b::cde"))!=-1) { printf("optind:%d\n",optind); printf("optarg:%s\n",optarg); printf("ch:%c\n",ch); switch(ch) { case 'a': printf("option a:'%s'\n",optarg); break; case 'b': printf("option b:'%s'\n",optarg); break; case 'c': printf("option c\n"); break; case 'd': printf("option d\n"); break; case 'e': printf("option e\n"); break; default: printf("other option:%c\n",ch); } printf("optopt+%c\n",optopt); } }
在终端执行以下启动命令:
./a.out -a1234 -b432 -c -d
输出如下:
optind:2 optarg:1234 ch:a option a:'1234' optopt+ optind:3 optarg:432 ch:b option b:'432' optopt+ optind:4 optarg:(null) ch:c option c optopt+ optind:5 optarg:(null) ch:d option d optopt+
main(int argc,char *argv[])中的argc是一个整型,argv是一个指针数组,argc记录argv的大小。上面的例子中。
argc=5;argv[0]=./a.outargv[1]=-a1234argv[2]=-b432argv[3]=-cargv[4]=-d
getopt函数原型:
getopt(int argc,char *const argv[],const char *optstring)
optstring是一段自己规定的选项串,例如本例中的”a:b::cde”,表示可以有,-a,-b,-c,-d,-e这几个参数“:”表示该选项必须带有额外的参数,全域变量optarg会指向此额外参数,“::”标识该额外的参数可选(有些Uinx可能不支持“::”)全域变量optind指示下一个要读取的参数在argv中的位置如果getopt()找不到符合的参数则会印出错信息,并将全域变量optopt设为“?”字符如果不希望getopt()印出错信息,则只要将全域变量opterr设为0即可
判断文件的访问权限
头文件:
int _access( const char *path, int mode ); int _waccess( const wchar_t *path, int mode );
参数:
path 文件或目录路径
ode 访问权限设定
返回值:
如果文件具有指定的访问权限,则函数返回 0
如果文件不存在或者不能访问指定的权限,则返回-1
当path为文件时,_access函数判断文件是否存在,并判断文件是否可以用mode值指定的模式进行访问
当path为目录时,_access只判断指定的目录是否存在
mode的值和含义:
00 检查文件是否存在
02 写权限
04 读权限
06 读写权限
localtime()函数
链接:/shellching/article/details/8114266
SetConsoleCtrlHandler控制台处理函数
链接:/blog/661431
inline函数
在函数声明或定义中函数返回类型前加上关键字inline即把min()指定为内联。
inline int min(int first, int secend) {/****/};
inline 函数对编译器而言必须是可见的,以便它能够在调用点内展开该函数。与非inline函数不同的是,inline函数必须在调用该函数的每个文本文件中定义。当然,对于同一程序的不同文件,如果inline函数出现的话,其定义必须相同。对于由两个文件compute.C和draw.C构成的程序来说,程序员不能定义这样的min()函数,它在compute.C中指一件事情,而在draw.C中指另外一件事情。如果两个定义不相同,程序将会有未定义的行为:
为保证不会发生这样的事情,建议把inline函数的定义放到头文件中。在每个调用该inline函数的文件中包含该头文件。这种方法保证对每个inline函数只有一个定义,且程序员无需复制代码,并且不可能在程序的生命期中引起无意的不匹配的事情
inline 说明这个函数是内联的,在编译过程中内联函数会直接被源代码替换,提高执行效率 如果类中的某个函数会被调用很多次或者放在循环中,那么建议将这个函数声明为内联,可以提高程序的运行效率
CreateDirectory创建文件目录
链接:/s/blog_618a89940101nl41.html
整形字符转换
strtoul函数
将字符串转换成无符号长整型数,类似的函数还有atof,atoi,atol,strtod,strtol
原型:
unsigned long strtoul(const char *nptr,char **endptr,int base);
[说明]strtoul()会将参数nptr字符串根据参数base来转换成无符号的长整型数。参数base范围从2至36,或0。参数base代表采用的进制方式,如base值为10则采用10进制,若base值为16则采用16进制数等。当base值为0时会根据情况选择用哪种进制:如果第一个字符是’0’,就判断第二字符如果是‘x’则用16进制,否则用8进制;第一个字符不是‘0’,则用10进制。一开始strtoul()会扫描参数nptr字符串,跳过前面的空格字符串,直到遇上数字或正负符号才开始做转换,再遇到非数字或字符串结束时(”)结束转换,并将结果返回。若参数endptr不为NULL,则会将遇到不合条件而终止的nptr中的字符指针由endptr返回。[返回值]返回转换后的长整型数,否则返回ERANGE并将错误代码存入errno中
_ultoa函数
转换一个无符号长整型数为字符串
原型:
char *ultoa(unsigned long value, char *string, int radix);
示例:
#include#includeint main( void ){unsigned long lnumber = 3123456789L;char string[25];ultoa(lnumber,string,10);printf("string = %s unsigned long = %lu\n",string,lnumber);return 0;}
将lnumber转换成字符型,然后添加到字符数组string中
进程或线程相关函数
SetPriorityClass
设置进程的优先级
函数原型:
BOOL WINAPI SetPriorityClass(_In_ HANDLE hProcess,_In_ DWORD dwPriorityClass);
【参数】
hProcess
进程句柄,可以通过GetCurrentProcess等函数获取dwPriorityClass
优先级级别,如:ABOVE_NORMAL_PRIORITY_CLASS(在普通优先级之上)
获取当前进程或线程句柄或ID
函数如下:
{返回当前线程的虚拟句柄}
GetCurrentThread: THandle;{返回当前线程 ID}
GetCurrentThreadId: DWORD;{返回当前进程的虚拟句柄}
GetCurrentProcess: THandle;{返回当前进程 ID}
GetCurrentProcessId: DWORD;
详见链接:(/del/archive//03/10/1098311.html)
CreateToolhelp32Snapshot进程快照
获取进程信息为指定的进程、进程使用的堆[HEAP]、模块[MODULE]、线程建立一个快照。
原型:
HANDLE WINAPI CreateToolhelp32Snapshot(DWORD dwFlags, //用来指定“快照”中需要返回的对象,可以是TH32CS_SNAPPROCESS等DWORD th32ProcessID //一个进程ID号,用来指定要获取哪一个进程的快照,当取系统进程列表或获取当前进程快照时可以设为0);
【参数】
1、dwFlags
指定快照中包含的系统内容,这个参数能够使用下列数值(常量)中的一个或多个:
TH32CS_INHERIT - 声明快照句柄是可继承的;TH32CS_SNAPALL - 在快照中包含系统中所有的进程和线程;TH32CS_SNAPHEAPLIST - 在快照中包含在th32ProcessID中指定的进程的所有的堆;TH32CS_SNAPMODULE - 在快照中包含在th32ProcessID中指定的进程的所有的模块;TH32CS_SNAPPROCESS - 在快照中包含系统中所有的进程;TH32CS_SNAPTHREAD -在快照中包含系统中所有的线程;
2、th32ProcessID
指定将要快照的进程ID。如果该参数为0表示快照当前进程。该参数只有在设置了TH32CS_SNAPHEAPLIST或者TH32CS_SNAPMODULE后才有效,在其他情况下该参数被忽略,所有的进程都会被快照;
【返回值】
调用成功,返回快照的句柄,调用失败,返回INVALID_HANDLE_VALUE
获取进程中的线程或线程枚举
进程为线程提供生存的空间,线程为进程的存在提供了时间,没有线程的存在进程没有存在的意义,一个进程中可以同时具有多个线程,但必须有一个线程,进程生成时创建的第一个线程被称之为主线程,它可以创建子线程,子线程还可以创建孙线程。
通过函数CreateToolhelp32Snapshot创建进程快照;
通过函数Thread32First获取第一个线程信息;
通过函数Thread32Next获取下一个线程信息;
原型:
BOOL WINAPI Thread32First(HANDLE hSnapshot, LPTHREADENTRY32 lpt2)BOOL WINAPI Thread32Next(HANDLE hSnapshot, LPTHREADENTRY32 lpte);
OpenThread打开线程
用于打开一个现有线程对象。
原型:
HANDLE WINAPI OpenThread(_In_ DWORD dwDesiredAccess,_In_ BOOL bInheritHandle,_In_ DWORD dwThreadId );
【参数】
dwDesiredAccess 线程对象的访问。此访问权限检查线程的安全描述符。这个参数可以是一个或多个线程访问权限;bInheritHandle 如果这个值是true的,这个进程将继承该句柄的进程。否则,进程不继承此句柄;dwThreadId 要打开的线程的标识符;
SetThreadAffinityMask 指定线程的运行CPU
该函数实现为各个线程设置亲缘性屏蔽,即为线程指定运行的CPU
原型:
DWORD_PTR SetThreadAffinityMask ( HANDLEhThread, // handle to thread DWORD_PTR dwThreadAffinityMask // thread affinity mask );
【参数】
hThread 用于指明要限制的线程标识;dwThreadAffinityMask 用于指明线程能够在哪个CPU上运行,必须是进程的亲缘性屏蔽的相应子集,例如,可能有一个包含4个线程的进程,它们在拥有4个CPU的计算机上运行。如果这些线程中的一个线程正在执行非常重要的操作,而你想增加某个CPU始终可供它使用的可能性,为此你对其他3个线程进行了限制,使它们不能在CPU 0上运行,而只能在CPU 1、2和3上运行。因此,若要将3个线程限制到CPU 1、2和3上去运行,可以这样操作:
//线程0只能在cpu 0上运行 SetThreadAffinityMask(hThread0,0x00000001); //线程1,2,3只能在cpu 1,2,3上运行 SetThreadAffinityMask(hThread1,0x0000000E); SetThreadAffinityMask(hThread2,0x0000000E); SetThreadAffinityMask(hThread3,0x0000000E);
【返回值】
线程的前一个亲缘性屏蔽
时间函数
1 得到当前UTC时间void GetSystemTime(LPSYSTEMTIME lpSystemTime);
2 得到当地时间
void GetLocalTime(LPSYSTEMTIME lpSystemTime);
3 SYSTEMTIME转成FILETIME
BOOL SystemTimeToFileTime(const SYSTEMTIME* lpSystemTime,LPFILETIME lpFileTime);
4 FILETIME转成SYSTEMTIME
BOOL FileTimeToSystemTime(const FILETIME* lpFileTime,LPSYSTEMTIME lpSystemTime);
5 当地时间转成UTC时间
BOOL LocalFileTimeToFileTime(const FILETIME* lpLocalFileTime,LPFILETIME lpFileTime);
6 UTC时间转成当地时间
BOOL FileTimeToLocalFileTime(const FILETIME* lpFileTime,LPFILETIME lpLocalFileTime);
7 获取系统运行时间
CopyBOOL WINAPI GetSystemTimes(__out_opt LPFILETIME lpIdleTime, //空闲时间__out_opt LPFILETIME lpKernelTime, //内核时间__out_opt LPFILETIME lpUserTime //用户时间);
【CUP利用率计算方法】
总时间=内核时间+用户时间;
cpu利用率=(总时间-空闲时间)/总时间
获取系统内存信息
函数GlobalMemoryStatusEx和GlobalMemoryStatus。
当系统内存大于4G时,只能使用函数GlobalMemoryStatusEx获取内存信息。
函数原型:
BOOL WINAPI GlobalMemoryStatusEx(LPMEMORYSTATUS lpBuffer)
参数:是一个指向MEMORYSTATUSEX结构体的指针
MEMORYSTATUSEX结构如下:
typedef struct _MEMORYSTATUSEX {DWORDdwLength; //本结构长度DWORDdwMemoryLoad; //已用内存百分比DWORDLONG ullTotalPhys; //物理内存总量DWORDLONG ullAvailPhys; //可用物理内存DWORDLONG ullTotalPageFile; //页交换文件最多能放的字节数DWORDLONG ullAvailPageFile; //页交换文件中尚未分配给进程的字节数DWORDLONG ullTotalVirtual; //用户区总的虚拟地址空间DWORDLONG ullAvailVirtual; //用户区当前可用的虚拟地址空间DWORDLONG ullAvailExtendedVirtual; //保留值,设为0} MEMORYSTATUSEX, *LPMEMORYSTATUSEX;
ullAvailVirtual这个值是这个结构中唯一一个与该进程有关的成员,所有的其他成员
都适用于整个系统,为了计算这个值GlobalMemoryStatus会把调用进程的地址空间中所有的闲置区域都加起来。
WSAStartup和WSACleanup
通常这两个函数要搭配使用。
WSAStartup的功能是初始化Windows socket DLL,WSACleanup是来解除与Socket库的绑定并且释放Socket库所占用的系统资源。
函数原型:
int PASCAL FAR WSAStartup( WORD wVersionRequested, LPWSADATA lpWSAData );
【参数】
wVersionRequested 欲使用的 Windows Sockets API 版本,高位字节指出副版本(修正)号,低位字节指明主版本号;lpWSAData 指向WSADATA数据结构的指针,用来接收Windows Sockets实现的细节;
【返回值】
成功——0
失败——-WSASYSNOTREADY / WSAVERNOTSUPPORTED / WSAEINVAL
InterlockedIncrement16和InterLockedDecrement
属于互锁函数,用在同一进程内,需要对共享的一个变量做加法或减法的时候,
防止其他线程访问这个变量,是实现线程同步的一种办法
InterlockedIncrement函数可以实现对变量的同步操作,当多个线程或进程操作同一个变量时,此函数可以保证对操作的变量同步,对变量进行加法操作。
如:
变量 Long value =0;
正常情况下的加减操作:value+=1;
1:系统从Value的空间取出值,并动态生成一个空间来存储取出来的值;
2:将取出来的值和1作加法,并且将和放回Value的空间覆盖掉原值。加法结束。
如果此时有两个Thread ,分别记作threadA,threadB;
1:threadA将Value从存储空间取出,为0;
2:threadB将Value从存储空间取出,为0;
3:threadA将取出来的值和1作加法,并且将和放回Value的空间覆盖掉原值。加法结束,Value=1。
4:threadB将取出来的值和1作加法,并且将和放回Value的空间覆盖掉原值。加法结束,Value=1。
最后Value =1 ,而正确应该是2;这就是问题的在,InterLockedIncrement 能够保证在一个线程访问变量时其它线程不能访问。
用于增减变量的并不是常用的Inc/Dec过程,而是用了InterlockedIncrement/InterlockedDecrement这一对过程,它们实现的功能完全一样,都是对变量加一或减一。但它们有一个最大的区别,那就是InterlockedIncrement/InterlockedDecrement是线程安全的。即它们在多线程下能保证执行结果正确,而Inc/Dec不能
如果觉得《C++ 常用生僻函数小记》对你有帮助,请点赞、收藏,并留下你的观点哦!