switch/assert/main参数/语句合法性/exit和return/栈大小/缓冲区溢出

1.switch
如果找到了与之匹配的入口,那么将执行,否则将执行default;
如果没有匹配的入口,将执行default;
如果执行完后的语句没有break,将继续执行下一个入口的语句。

void fun()
{
   for(int i = 0; i < 3;++i)
   {
      switch(i)
   {
      case 0:
                cout<<i<<" "; 
      case 2:
                cout<<i<<" "; 
      default:
                cout<<i<<" "; 
     }
    }
}

执行结果:000 1 22
当case == 0时,匹配到第一条语句,执行完后,没有遇到break,接下来继续执行其他语句,除非遇到break或者switch结束;
当case == 1时,没有匹配到语句,所以只好执行default语句,然后语句结束;
当case == 2时,匹配到第二条语句,执行完后没有遇到break,switch也没结束,所以将继续执行default语句


2.
ASSERT()是中的宏,只在DEBUG版本中有效,在relase版本中无效
assert()是中的一个标准函数,既可以在debug中使用也可以在relase中使用

注意:
(1)每个assert()一次只能检验一个条件,因为对多个条件进行检验,出现断言错误,就不知道到底是哪条句子有错了  比如assert( value>0 && value <100)
(2)assert(i++>100) 这样的句子不要使用,如果断言前i=99,那么i++这句语句将不会被执行


3.main函数的参数问题
switch/assert/main参数/语句合法性/exit和return/栈大小/缓冲区溢出
argc:代表的是参数的个数,如果不传递参数,默认为可执行程序的名字,也就是argv[0],即最小为1
argv:  中保存的是传递的参数,是字符串类型,以空格为分界线,argv[0]是可执行程序的名字

C++中静态变量,全局变量,全局对象都是在mian函数执行前完成的初始化


4.
判断(a++)+=a;是否合法:
左值:指的是变量的内存名称,出现在等号的左边
右值:指的是内存中保存的数据,出现在等号的右边

左值可以为右值,但是右值不能为左值

++a和a++的区别:
++a:先取a的地址,将内存中的数据进行+1的操作,然后将内存最终的值放到寄存器中
a++:取a的地址,将a的数据放在寄存器中,然后在对内存中值进行的++操作

所以++a可以作为可以作为左值使用,但是a++就不行


5.

return:表示返回的是一个函数调用,仅仅代表函数调用结束,如果是在main中return 代表该进程结束
exit:表示退出这个程序,exit(n),n==0时代表程序正常退出,n==1时代表内存分配失败而退出程序,n==2时代表文件打开失败而退出程序,程序员可以根据不同的退出码判断区别退出的原因。


6.栈的大小:
window平台,栈的大小默认为2M
Linux平台的栈的大小默认为8M,可以 用命令  ulimit -s   来设置栈的大小


7.缓冲区溢出
所谓缓冲区就是系统分配的一块连续内存的,
而缓冲区溢出是指向缓冲区写入的数据太多太长,导致数据溢出缓冲区将函数的栈帧上的其他数据覆盖掉
switch/assert/main参数/语句合法性/exit和return/栈大小/缓冲区溢出

假设我给buff中写入AAA 自动补齐\0  这样没什么问题,如果我写入4个字符,那么将发送栈溢出,将返回主函数栈帧的地址修改,如果修改成其他函数的入口函数,从而如果执行到其他函数,将发生严重的后果


8.sizeof和strlen的区别:
1.sizeof是关键字,会在编译的时候进行处理,而strlen是函数,是在运行时计算的
2.当一个数组名作为参数传递时会退化为指针,但是由于sizeof是关键字,所以数组名不会退化,也就是说
char arr[10];      sizeof(arr)为10 B。
3.strlen的参数只能以char *为参数类型,并且以\0结尾的字符串
4 .引用和指针,sizeof一个引用,计算出来的是对象或者变量本身占用的内存大小,而sizeof一个指针,计算出来的是指针的大小,32位的平台下位4B


9.如何开启内存对齐呢
#pragma   pack( n ),告诉编译器按照n字节对齐


10.
数组与指针区别:
char a[]="helloworld";  a[0] = 'X';  是可以的
char *p ="helloworld"; p[0] = 'y';是错误的   因为是常量字符串所以不允许更改

char a[]="helloworld";    sizeof(a) = 11;    不会退化
char *p ="helloworld";    sizeof(p) = 4 ;     p本身就是个指针


11.
怎么判断一个整数的二进制含有多少个1

int   fun( int x )
{
     int count = 0;
     while( x )
     {
          count++;
          x = x&(x - 1);
     }
     return count;
}





11.定义头文件使用的宏
#ifndef
#define 
#endif
作用:如果一个项目中的俩个c文件都包含了一个头文件,如果将这俩个文件链接成一个,必然会有名字的冲突的问题,这样就不会发生符号重定义的问题。



12.
宏定义求平方的错误实例:
#define SQR(a)   a*a
假如是这样调用的呢: SQR(1+3,2+5);   得到的结果为12
如果是函数调用就不一样了:实参给形参传值时会把表达式的值计算出来然后给形参

13.
王者荣耀是TCP的还是UDP的?
答:UDP

在注重即时性的游戏中,对于延迟的要求是很苛刻的,我们可以丢包,但是如果我们收到了比丢掉的包更新的包的话,我们完全可以不管丢掉的包。我们只关注当前数据。

这里我们来假设一个最简单的多人游戏的模型。比如一个FPS游戏,你在客户段每次将输入的数据(比如前进,跳跃,开火)发送到服务器端,然后服务器端将玩家当前的位置和情况发回给客户端来做显示。

在这个最简单的模型中,只要有一个包丢失了,所有的东西都必须停下来等包的重发,任何操作都得停掉,你不能移动也不能射击。等到这个包到达的时候,你总算能继续操作了。但是可能你会发现还有一堆等等待重发的包在排队,于是你只好继续等,而且可能你收到的这个重发包对游戏来说已经失去时效性,完全没意义了。这样的游戏你能忍吗?

不幸的是你对TCP协议的这个行为完全无能为力。这是TCP协议的本性,就是它保证了TCP协议的可靠性的。

我们不需要这样无法订制的可靠性协议。我们需要自己进行订制丢包时的处理原则。这也是我们在开发游戏时,避免使用TCP协议的原因。

是否可以混合使用TCP和UDP协议呢?

上面的结论中,我们可以明确知道,一些类似玩家操作,玩家位置的时效性相关数据,我们必须不能使用TCP协议。但是有些数据确是必须保证可靠性的,那我们是否可以使用TCP协议来做同步呢?

这个想法是很好的,我们可以在玩家操作等即时性很强的数据上使用UDP协议,在玩家AI,数据加载,玩家对话等序列性很强的数据上使用TCP。如果你愿意的话,甚至可以为不同的AI创建不同的TCP连接,以免一个AI的丢包会影响的另外一个AI的即时性。

看上去这是一个不错的思路。但是这仅仅是看上去而已。由于TCP和UDP都是基于IP协议的,事实上他们在底层会互相干扰。

结论:
在游戏中仅仅使用UDP作为网络协议,即使要使用TCP也是自己在UDP的基础上实现一种类TCP的协议。这也是现代游戏中流行的网络架构









猜你喜欢

转载自blog.csdn.net/KingOfMyHeart/article/details/88893419