假设 y = ax + b 其中y是除数,x是被除数,a是商,b是余数
记住一点就是:b 应该与 a 同号,也就是说,余数永远和被除数同号
-5 = -1 * 3 + -2
-5 = 1 * -3 + -2
这样就能得到对应的商和余数了,不管被除数是正还是负
字节序分为大小端,注意这里指的是字节的顺序,再往细分就不关注了,也就是说如果 0x11223344 的一个值在内存中以 低地址 存放 11 高地址存放 44,那么就是大端。 如果是高地址存放 11 低地址存放 44 那就是小端。
计算机处理字节序的时候,不知道什么是高位字节,什么是低位字节。它只知道按顺序读取字节,先读第一个字节,再读第二个字节。
如果是大端字节序,先读到的就是高位字节,后读到的就是低位字节。小端字节序正好相反。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
union{
short s;
char c[sizeof(short)];
}un;
un.s = 0x0102;
if(sizeof(short) == 2)
{
if(un.c[0] == 1 && un.c[1]== 2) //将高序字节地址存储在起始地址,成为大端字节序
printf("big-endian\n");
else if(un.c[0] == 2 && un.c[1]== 1) //将低序字节存储在起始地址,为小端字节序
printf("little-endian\n");
}
else
{
printf("sizeof(short)= %d\n",sizeof(short));
}
return 0;
}位段,就是C语言允许在一个结构体中以位为单位来指定其成员所占内存长度。
位段的定义的格式为:type [varName]:num 其中的type只能为int,unsigned int,signed int 三种类型中的一种。而varName 是可选的,可以没有。num是所占的位数不可以超过类型所占位数的最大值。
typedef struct node {
unsigned int a:1;
char b; //在一个位段存储单元中能够存下所有的成员,所以占4Byte
int c:1;
unsigned int :0; // 占位为0的位段必须是无名位段
int :6; // 占6位的无名位段
int d:2;
unsigned int e:2;
} S;对于位段的对齐规则为:后面的字段将紧邻前一个字段存储,直到不能容纳为止。
整形
一个小例子:
int a = 65;
char *s = (char *)(&a);
printf("%s",s);这里会输出A,代码虽然少,但是考点很多,一个是整型的存储,一个是大小端,一个是%s 的结束符,首先是整型的存储,对于整数,它的补码等于原码,所以 65 的存储是 0x00041; 然后是字节序,明显s指向的是a的低地址的数据,因为是小端32位,所以指向的也就是a的最低有效位的数据 0x41,然后后面是 0x00(结束符),所以会输出0x41=65为ASCII码的字符后遇到结束符然后就退出了。
浮点型有 float 和 double 两种,前面是32位,后面是64位,对于float类型,是 1 符号 + 8 指数 + 23 尾数,而对于64位则是 1 符号 + 11 指数 + 52 尾数。对于浮点数的存储就是把首位都变为1,比如 8.25 = 1000.01,就是 变成 1.00001 * 2^3,其中符号位为0,指数位为3+127=130=1000 0010(相当于其中的首位1是符号位),其中加127就是因为指数部分会出现负的所以对于正数就应该+127,尾数位为00001因为首位肯定是1所以省略了。
很明显,如果使用数组名作为形参,会退化为指针进行传值,如何解决这个问题。
例如下面的代码:
void arrFun(char a[])
{
cout<<sizeof(a)<<endl;
}
void arrRefFun(auto &a)
{
cout<<sizeof(a)<<endl;
}
template <unsigned N>
void arrTemplateFun(const char (&a)[N])
{
cout<<N<<endl;
}
int main(int argc, char *argv[])
{
char a[10] = "abcd";
char *b = new char[10] ();
arrFun(a);// 4
arrRefFun(a);// 10
arrTemplateFun("abcd");// 5
arrTemplateFun(a);// 10
arrFun(b);// 4
arrRefFun(b);// 4
//arrTemplateFun(b);// 错误用法,不能实例化模板
return 0;
}其中第一种方式就是使用的是数组名传参,可以看到输出的是指针的大小为4byte,数组的维度信息丢失了
第二种方式使用新标准的auto的方式,得到的类型就是实参的类型,也就是说,如果又两个 数组 char a[10] char b[20] 使用auto对两者进行类型推断得到的两种类型是不一样的,一个是 维度为10 的数组,一个是维度是20的数组
第三种方式是通过非类型模板的形式进行模板实例化,这种方式有限制,只有维度是字面值,可以推断出N 的大小的形式才能使用,不过对于解决这个问题这种限制可以忽略。也就是说我们不能使用一个 普通局部变量 或 动态对象 作为 指针 或 引用 的 非类型模板参数 的 实参。