第一部分操作符sizeof
有个概念要说下,
指针不同于普通变量,指针存的是地址,而地址的范围只和机器字以及系统有关
在32位系统中,所有指针都是4B
在64位系统中,所有指针都是8B,普通变量仍然为4字节
下面的程序运行在64bit系统中结果:
1 #include
2
3 void main(void)
4 {
5 int a[] = {1,2,3,4};
6 printf("%ld\n",sizeof(int)); //4
7 printf("%ld\n",sizeof(int *)); //8
8 printf("%ld\n",sizeof(a)); //16 a是数组名字,代表整个数组
9 printf("%ld\n",sizeof(a+0)); //8 数组名是和第一个元素地址一样,a+0是第二个元素的地址也是一个指针
10 printf("%ld\n",sizeof(*a)); //4 整型变量
11 printf("%ld\n",sizeof(a+1)); //8 同上
12 printf("%ld\n",sizeof(a[1])); //4 整型变量
13 printf("%ld\n",sizeof(&a)); //8 指针地址
14 printf("%ld\n",sizeof(*&a)); //16 代表数组a
15 printf("%ld\n",sizeof(&a+1)); //8 是个指针
16 printf("%ld\n",sizeof(&a[0])); //8 是个指针
17 printf("%ld\n",sizeof(&a[0]+1)); //8 是个指针
18 }
~
以上参考32位的结果是,引用其他大神写的
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a)); //16
printf("%d\n",sizeof(a+0)); //4
printf("%d\n",sizeof(*a)); //4
printf("%d\n",sizeof(a+1)); //4
printf("%d\n",sizeof(a[1])); //4
printf("%d\n",sizeof(&a)); //4
printf("%d\n",sizeof(*&a)); //16
printf("%d\n",sizeof(&a+1)); //4
printf("%d\n",sizeof(&a[0])); //4
printf("%d\n",sizeof(&a[0]+1)); //4
---------------------
作者:ty6693
来源:CSDN
原文:https://blog.csdn.net/ty6693/article/details/86699176
版权声明:本文为博主原创文章,转载请附上博文链接!
另外数组名作为形参使用,将数组名当作指针处理。
第二部分数组名和数组地址
12 int a[] = {1,2,3,4};
13
14 printf("addr of a = 0x%p\n", a);
15 printf("addr of &a = 0x%p\n", &a);
16 printf("addr of a + 1 = 0x%p\n", a + 1);
17 printf("addr of &a + 1 = 0x%p\n", &a + 1);
18 printf("addr of &a[3] = 0x%p\n", &a[3]);
结果:
addr of a = 0x0x7ffc894f2b00
addr of &a = 0x0x7ffc894f2b00
addr of a + 1 = 0x0x7ffc894f2b04
addr of &a + 1 = 0x0x7ffc894f2b10
addr of &a[3] = 0x0x7ffc894f2b0c
以下内容为转载
具体地址:https://www.cnblogs.com/xiaodingmu/p/7200867.html
首先a是一个数组名,当看到这个a与&a时,一般我们的理解都是这个数组的首地址。没错,如果加上打印的话,确实两个值是一样的。
不过&a是整个数组的首地址,a则是数组首元素的地址,虽然值一样,但是意义却不相同。
由此我们可以区分a+1和&a+1的区别了。
&a+i = a + i*sizeof(a);
a+i = a +i*sizeof(a[0]);
第三部分字节对齐:
从网上摘了一段:
如果一个32位的数据没有存放在4字节整除的内存地址处,那么处理器就需要2个总线周期对其进行访问,显然访问效率下降很多。因此,通过合理的内存对齐可以提高访问效率。为使CPU能够对数据进行快速访问,数据的起始地址应具有“对齐”特性。比如4字节数据的起始地址应位于4字节边界上,即起始地址能够被4整除。此外,合理利用字节对齐还可以有效地节省存储空间。但要注意,在32位机中使用1字节或2字节对齐,反而会降低变量访问速度。因此需要考虑处理器类型。还应考虑编译器的类型。在VC/C++和GNU GCC中都是默认是4字节对齐。
记住2点一是默认4字节对齐二是提高访问效率。
我使用的机器为64位的,例子中所有的指针的大小均为8字节
187 struct test {
188 int num; //4 字节
189 int pcname; //4字节
190 char a[2]; //本身2个字节,但是因为对齐 所以此元素占4字节
191 short sba[4]; //short占2字节一共8字节
192 };
结果:
size of struct test = 20
187 struct test {
188 int num; //4字节 补4个字节 一共8字节
189 char *pcname; //8字节 影响前后2元素的字节,补齐的字节数。
190 char a[2]; //本身2字节,因为对齐8字节补,补6个字节
191 short sba[4];//short占2字节一共8字节
192 };
结果
size of struct test = 32
187 struct test {
188 int num; //4字节
189 char a[2]; //4字节
190 short sba[4];//8字节
191 char *pcname;//8字节
192 };
结果
size of struct test = 24
187 struct test {
188 char num;
189 char num1;
190 char num2;
191 char num3;
195 };
size of struct test = 4
首先,我们给出四个概念:
1)数据类型自身的对齐值:就是基本数据类型的自身对齐值,比如char类型的自身对齐值为1字节,int类型的自身对齐值为4字节。
2)指定对齐值:预编译命令#pragma pack (value)指定的对齐值value。
3)结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值,比如以上的struct A的对齐值为4。
4)数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中较小的那个值。
其实,除了结构体之外,整个程序在给每个变量进行内存分配时都会遵循对齐机制,也都会产生内存空间的浪费。但我们要知道,这种浪费是值得的,因为它换来的是效率的提高。
以上分析都是建立在程序默认的对齐值基础之上的,我们可以通过添加预定义命令#pragma pack(value)来对对齐值进行自定义,比如#pragma pack(1),对齐值变为1,此时内存紧凑,不会出现内存浪费,但效率降低了。效率之所以降低,是因为:如果存在更大字节数的变量时(比1大),比如int类型,需要进行多次读周期才能将一个int数据拼凑起来。