目录
- 一 进程相关函数
- 1 exit、_exit和return
- 2 assert()宏用法
- 3 sockpair
- 4 access
- 5 sleep函数
- 二 输出输入
- 1 C/C++输入输出函数
- 2 变量地址和指针
- 3 cout进制输出
- 4 有关缓冲区的注意点
- 三 参数解析函数
- 1 getopt_long
- 2 basename(分析路径成员 )
- 3 getopt(分析命令行参数)
- 四 字符操作函数及其实现
- 1 Strcat函数
- 2 Strcpy函数
- 3 Strcmp函数
- 4 Strlen函数
- 1 strstr()
- 2 strcmp()
- 3 strcasecmp()
- 4 index()
- 五 随机数
- 六 main函数
- 1 main函数与WinMain函数区别
- 2 main函数与wmain函数 | WinMain函数与wWinMain函数的区别
- 3 _tmain函数与main/wMain | _tWinMain函数与WinMain/wWinMain的区别
- 七 C++中L和_T()之区别
- 八 获取执行文件路径
一 进程相关函数
1 exit、_exit和return
exit(0):正常运行程序并退出程序;exit(1):非正常运行导致退出程序;return:返回函数。
return是语言级别的,它表示了调用堆栈的返回;而exit是系统调用级别的,它表示了一个进程的结束。
在stdlib.h中exit函数是这样子定义的:void exit(int status)。这个系统调用是用来终止一个进程的,无论在程序中的什么位置,只要执行exit,进程就会从终止进程的运行。讲到exit这个系统调用,就要提及另外一个系统调用,_exit,_exit()函数位于unistd.h中,相比于exit(),_exit()函数的功能最为简单,直接终止进程的运行,释放其所使用的内存空间,并销毁在内存中的数据结构,而exit()在于在进程退出之前要检查文件的状态,将文件缓冲区中的内容写回文件。
非主函数中调用return和exit效果很明显,但是在main函数中调用return和exit的现象就很模糊,多数情况下现象都是一致的。
2 assert()宏用法
assert
是宏,而不是函数。在C的assert.h
头文件中。原型定义:
#define assert(expr)
((expr)
?__ASSERT_VOID_CAST(0)
:__assert_fail(__STRING(expr),__FILE__,__LINE__,__ASSERT_FUNCTION))
/*DefinedInGlibc2.15*/
assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort来终止程序运行。windows平台上assert宏只在release模式下有效。Linux上则没有这个限制,无论Debug还是release模式assert都生效,但是如果你想让assert失效,编译的时候加上-DNDEBUG
即可。
#define NDEBUG
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cassert>
using namespace std;
int main(int argc, char *argv[])
{
bool is = false;
assert(is);
printf("hell");
return 0;
}
//输出:hell
这个宏通常原来判断程序中是否出现了明显非法的数据,如果出现了终止程序以免导致严重后果,同时也便于查找错误。
3 sockpair
4 access
access函数检查调用进程是否可以对指定的文件执行某种操作。原型:
int access(const char * pathname, int mode)
pathname:需要检测的文件路径名;mode:需要的操作模式,取值如下:
F_OK 值为0,判断文件是否存在
X_OK 值为1,判断对文件是可执行权限
W_OK 值为2,判断对文件是否有写权限
R_OK 值为4,判断对文件是否有读权限
注:后三种可以使用或“|”的方式,一起使用,如W_OK|R_OK
成功执行时,返回0。失败返回-1,errno被设为以下的某个值
EINVAL: 模式值无效
EACCES: 文件或路径名中包含的目录不可访问
ELOOP : 解释路径名过程中存在太多的符号连接
ENAMETOOLONG:路径名太长
ENOENT:路径名中的目录不存在或是无效的符号连接
ENOTDIR: 路径名中当作目录的组件并非目录
EROFS: 文件系统只读
EFAULT: 路径名指向可访问的空间外
EIO:输入输出错误
ENOMEM: 不能获取足够的内核内存
ETXTBSY:对程序写入出错
5 sleep函数
在linux编程中,有时候会用到定时功能,常见的是用sleep(time)函数来睡眠time秒;但是这个函数是可以被中断的,也就是说当进程在睡眠的过程中,如果被中断,那么当中断结束回来再执行该进程的时候,该进程会从sleep函数的下一条语句执行;这样的话就不会睡眠time秒了。
#include <unistd.h>
unsigned int sleep (unsigned int seconds);//n秒
int usleep (useconds_t usec);//n微秒
sleep(time)返回值是睡眠剩下的时间。
以下情况不会中断。
do{
time = sleep(time);
}while(time > 0);
二 输出输入
1 C/C++输入输出函数
1. 缓冲区回车符
在C++中如果采用cin进行输入,则在缓存区留下回车字符,可以使用cin.get()或者是gets()读出。
2. cin类型不符
istream类重载了抽取运算符<< ,>>, 所以cin >> 支持c++内置的所有基本数据类型。cin对象将标准输入表示为字节流,然后根据抽取运算符<<(本质就是一个函数)的参数类型对字节流进行类型转换,转换为所需的类型。如果输入的前面一部分字符为空白(空格、换行符、和制表符),他们会跳过,直到遇到非空白字符。当输入没有满足程序期望的时候,比如对于一个int类型的变量a,却输入字符H,这种情况下,抽取运算发将不会改变变量a的值,并返回0,经常被放在循环条件中来终止循环。
3. cin.get()
cin.get()每次读取一整行并把由Enter键生成的换行符留在输入缓冲区中。
4. cin.getline()
cin.getline()每次读取一整行,并把由Enter键生成的换行符抛弃,回车符并不留在缓冲区。
5. getline()
getline()每次读取到特定字符,并把特定字符抛弃,特定字符并不留在缓冲区。
getline()的原型是istream& getline ( istream &is , string &str , char delim );位于头文件<string>中。
其中 istream &is 表示一个输入流,譬如cin;string&str表示把从输入流读入的字符串存放在这个字符串中(可以自己随便命名,str什么的都可以);char delim表示遇到这个字符停止读入,在不设置的情况下系统默认该字符为’n’,也就是回车换行符(遇到回车停止读入,且回车符会被丢弃)。
string line;
cout << "please cin a line:";
getline(cin, line, '#');
cout << "The line you give is:" << line <<endl;
参考
C++中cin的详细用法:https://blog.csdn.net/k346k346/article/details/48213811
6. gets和fgets
gets
函数会报错,所以需要使用fgets
。fgets
读入的字符里面会包含’n’,需要注意。
7. sprintf_s和sprintf
sprintf_s
和sprintf
的区别在于,sprintf只会将数据写入缓冲区,而sprintf_s首先会检查缓冲区大小,然后写入数据,并且将数据后一位置为0,而其他位置为-3,所以在第二个参数缓冲区大小的时候,需要大于写入的数据一个字节。
sprintf函数是一个变参函数,前两个函数有固定类型,会进行安全检查,后面的参数都不是类型安全的。使用的时候要小心了。
摘录网上的一个例子来说明:
假如我们想打印短整数(short)-1的内存16 进制表示形式,在Win32 平台上,一个short 型占2 个字节,所以我们自然希望用4 个16 进制数字来打印它:
short si = -1;
sprintf(s, "%04X", si);
产生“FFFFFFFF”,怎么回事?因为spritnf 是个变参函数,除了前面两个参数之外,后面的参数都不是类型安全的,函数更没有办法仅仅通过一个“%X”就能得知当初函数调用前参数压栈时被压进来的到底是个4 字节的整数还是个2 字节的短整数,所以采取了统一4 字节的处理方式,导致参数压栈时做了符号扩展,扩展成了32 位的整数-1,打印时4 个位置不够了,就把32 位整数-1 的8 位16 进制都打印出来了。如果你想看si 的本来面目,那么就应该让编译器做0 扩展而不是符号扩展(扩展时二进制左边补0 而不是补符号位):
sprintf(s, “%04X”, (unsigned short)si);就可以了。
2 变量地址和指针
- 普通变量
int a;
cout << &a;
- 数组变量
int a[20];
cout << &a;
cout << (int *)a;
cout<< (void *)a;
- 指针
int b = 10;
int *a = &b;
cout << (int *)a;
cout<< (void *)a;
3 cout进制输出
cout<<hex<<i<<endl; //输出十六进制数
cout<<oct<<i<<endl; //输出八进制数
cout<<dec<<i<<endl; //输出十进制数
cout << setbase(16) << t << endl;
4 有关缓冲区的注意点
int main()
{
printf("hello world!!");//此时可以打出hello world!!
exit(0); //exit(0);首先会刷新缓冲区,然后调用_exit(0)结束程序
}
int main()
{
printf("hello world!!");//此时打不出来 hello world
_exit(0);//其作用就是结束函数
}
int main()
{
printf("hello world!!n");//此时可以打出 hello world 因为“n”也有刷新缓冲区的作用
_exit(0);
}
int main()
{
puts("hello world!!");//此时可以打出 hello world 因为 puts()函数自带有“n”
_exit(0);
}
三 参数解析函数
1 getopt_long
2 basename(分析路径成员 )
c语言:#include <libgen.h>
c++语言:#include <string.h>
原型:char *basename(char *path);
函数说明:
basename把以 null 结尾的路径名分解为目录和文件名。basename 则返回最后一个 ‘/’ 后面的内容。如果路径名以 ‘/’ 结尾, 该 ‘/’ 被认为不是 路径名的一部分。如果路径名 path 不包含斜杠 ‘/’, basename 返回 path 的副本。如果路径名 path 是 “/”,basename均返回 “/”. 如果 路径名 path 是NULL指针或指向空串,则返回 “.”。basename 有可能更改 path 的内容, 因此如果需要保护原有路径名, 应该传送副本作为参数。此外, 返回的指针可能指向一块静态分配的内存, 会被下次调用覆盖。
3 getopt(分析命令行参数)
头文件:#include<unistd.h>
原型:int getopt(int argc,char * const argv[ ],const char * optstring);
函数说明:参数argc和argv是由main()传递的参数个数和内容。参数optstring 则代表欲处理的选项字符串。此函数会返回在argv 中下一个的选项字母,此字母会对应参数optstring 中的字母。如果选项字符串里的字母后接着冒号“:”,则表示还有相关的参数,全域变量optarg 即会指向此额外参数。如果getopt()找不到符合的参数则会印出错信息,并将全域变量optopt设为“?”字符,如果不希望getopt()印出错信息,则只要将全域变量opterr设为0即可。
短参数的定义:etopt()使用optstring所指的字串作为短参数列表,象"1ac:d::"就是一个短参数列表。短参数的定义是一个’-‘后面跟一个字母或数字,象-a, -b就是一个短参数。每个数字或字母定义一个参数。
其中短参数在getopt定义里分为三种:
1. 不带值的参数,它的定义即是参数本身。
2. 必须带值的参数,它的定义是在参数本身后面再加一个冒号。
3. 可选值的参数,它的定义是在参数本身后面加两个冒号 。
在这里拿上面的"1ac:d::"作为样例进行说明,其中的1,a就是不带值的参数,c是必须带值的参数,d是可选值的参数。
在实际调用中,’-1 -a -c cvalue -d’, ‘-1 -a -c cvalue -ddvalue’, ‘-1a -ddvalue -c cvalue’都是合法的。这里需要注意三点:
1. 不带值的参数可以连写,象1和a是不带值的参数,它们可以-1 -a分开写,也可以-1a或-a1连写。
2. 参数不分先后顺序,’-1a -c cvalue -ddvalue’和’-d -c cvalue -a1’的解析结果是一样的。
3. 要注意可选值的参数的值与参数之间不能有空格,必须写成-ddvalue这样的格式,如果写成-d dvalue这样的格式就会解析错误。
返回值:
getopt()每次调用会逐次返回命令行传入的参数。
当没有参数的最后的一次调用时,getopt()将返回-1。
当解析到一个不在optstring里面的参数,或者一个必选值参数不带值时,返回’?’。
当optstring是以’:‘开头时,缺值参数的情况下会返回’:’,而不是’?’ 。
范例:
#include <stdio.h>
#include <unistd.h>
int main(int argc, int *argv[])
{
int ch;
opterr = 0;
while ((ch = getopt(argc,argv,"a:bcde"))!=-1)
{
switch(ch)
{
case 'a':
printf("option a:'%s'n",optarg);
break;
case 'b':
printf("option b :bn");
break;
default:
printf("other option :%cn",ch);
}
}
printf("optopt +%cn",optopt);
}
四 字符操作函数及其实现
1 Strcat函数
char *strcat(char *strDest, const char *strScr) //将源字符串加const,表明其为输入参数
{
char * address = strDest; //该语句若放在assert之后,编译出错
assert((strDest != NULL) && (strScr != NULL)); //对源地址和目的地址加非0断言
while(*strDest) //是while(*strDest!=’ ’)的简化形式
{ //若使用while(*strDest++),则会出错,因为++是不受循环
strDest++; //约束的。所以要在循环体内++;因为要是*strDest最后指
} //向该字符串的结束标志’ ’。
while(*strDest++ = *strScr++)
{
NULL; //该循环条件内可以用++,
} //此处可以加语句*strDest=’ ’;有无必要?
return address; //为了实现链式操作,将目的地址返回
}
以下是在VC6.0中调试的例子,函数名用strcata代替。
#include <stdio.h>
#include <assert.h>
char *strcata(char *strDest,const char *strScr)
{
char * address = strDest;
assert((strDest != NULL) && (strScr != NULL));
while(*strDest)
{
strDest++;
}
while(*strDest++ = *strScr++) //(*strDest++ = *strScr++)!='