• 深入理解 C/C++ sizeof() 运算符


    过去有一段时间一直以为带个括号的 (sizeof())(C/C++) 的原生函数QAQ。

    其实不然,(sizeof) 同位运算符(^|&~!)一样是一种单目运算符,作用于变量或数组。

    在编译时编译器就会把 (sizeof()) 的内容转换成常数存入机器码中,不涉及函数的底层操作。

    用途

    sizeof 运算符可用于获取类、结构、共用体和其他用户自定义数据类型的大小。

    使用 sizeof 的语法如下:

    sizeof (data type)

    其中,data type 是要计算大小的数据类型,包括类、结构、共用体和其他用户自定义数据类型。

    sizeof 与 普通变量

    #include<bits/stdc++.h>
    using namespace std;
    int main() {
    	char char_var;
    	float float_var;
    	double double_var;
    	long double ldouble_var;
    	int int_var;
    	long long ll_var;
    
    	printf("sizeof char = %d
    ",sizeof(char_var));
    	printf("sizeof float = %d
    ",sizeof(float_var));
    	printf("sizeof double = %d
    ",sizeof(double_var));
    	printf("sizeof long double = %d
    ",sizeof(ldouble_var));
    	printf("sizeof int = %d
    ",sizeof(int_var));
    	printf("sizeof long long = %d
    ",sizeof(ll_var));	
    	return 0;
    } 
    

    输出结果:

    sizeof char = 1
    sizeof float = 4
    sizeof double = 8
    sizeof long double = 16
    sizeof int = 4
    sizeof long long = 8
    

    可以看出,编译器把 sizeof 的内容都替换成了变量占用的空间大小(单位为字节)。

    此外,作为一个运算符,在 sizeof 之后的变量名可以不用括号括起来,这样在概念上就不会和函数混淆了。

    sizeof 与 指针变量

    #include<bits/stdc++.h>
    using namespace std;
    int main() {
    	char *char_point;
    	double *double_point;
    	int *int_point;
    	long long ll_point;
    
    	printf("sizeof pchar = %d
    ",sizeof(char_point));
    	printf("sizeof pdouble = %d
    ",sizeof(double_point));
    	printf("sizeof pint = %d
    ",sizeof(int_point));
    	printf("sizeof plong long = %d
    ",sizeof(ll_point));	
    	return 0;
    } 
    

    输出结果:

    sizeof pchar = 8
    sizeof pdouble = 8
    sizeof pint = 8
    sizeof plong long = 8
    

    所有类型的指针变量在 (32) 位环境中占用四字节,在 (64) 位环境中占用 (8) 字节。
    我的编译器是 (x64)(64) 位)的,如果是 (x86) 编译器( (32) 位)下输出结果应该是 (4)

    sizeof 与 数组

    #include<bits/stdc++.h>
    using namespace std;
    int main() {
    	char char_arr[10]="233";
    	double double_arr[10]={0.0};
    	int int_arr[10]={0,1,2,3,4,5,6,7,8,9};
    	long long ll_arr[10];
    	
    	printf("sizeof arrchar = %d
    ",sizeof(char_arr));
    	printf("sizeof arrdouble = %d
    ",sizeof(double_arr));
    	printf("sizeof arrint = %d
    ",sizeof(int_arr));
    	printf("sizeof arrlong long = %d
    ",sizeof(ll_arr));	
    	return 0;
    } 
    

    输出结果:

    sizeof arrchar = 10
    sizeof arrdouble = 80
    sizeof arrint = 40
    sizeof arrlong long = 80
    

    sizeof 与结构体

    #include<bits/stdc++.h>
    using namespace std;
    int main() {
        struct Student {
            char name[20];
            bool sex; 
            int age;
            int num;
        }stu;
        
        printf("sizeof (Student)stu = %d
    ",sizeof(stu));
        return 0;
    } 
    

    输出结果:

    sizeof (Student)stu = 32
    

    name数组占用 (1*10=20) 个字节,两个int占用 (4*2=8) 个字节,一个bool占用 (1) 个字节,加起来应该是 (29)

    而程序输出了 (32) ,是不是编译器出问题了?

    其实这是正常的,因为结构体的成员变量占用的是一块连续的内存,但是为了保证对不同类型的变量寻址正确,编译器会在储存各变量地址时自动对齐,而不是每个变量的内存块都紧密相连。

    计算结构体大小需要了解一个名词偏移量,即结构体变量中成员的地址与结构体首地址的差(首个成员的地址),结构体内容每个成员(包括成员变量、函数、嵌套体)都拥有这一属性。

    结构体内偏移量的计算公式为:上一个成员的偏移量 + 上一个成员的占用字节数

    为了做到成员地址的对齐,编译器在编译程序时会遵照如下规则:

    结构体变量中成员的偏移量必须是该成员大小的整数倍,否则向上补齐

    还是用上面的例子,

    (name[20]) 为首元素,偏移量为 (0)
    (sex) 偏移量为 (0 + 20 = 20)(20 \% 1 = 0) ,无须补齐。
    (age) 偏移量为 (20 + 1 = 21)(21 \% 4 ≠ 0),偏移量向上补齐为整除 (4)(24)
    (num) 偏移量为 (24 + 4 = 28)(28 \% 4 = 0) ,无须补齐。

    最后算出该结构体占用的内存大小为 = num的偏移量 + num占用的大小 = (32) 字节。

    根据结构体变量地址对齐的这一特性,还可以知道在结构体中,结构体成员变量写的顺序会影响该结构体占用的空间大小。

    根据简单的数学知识,把内存占用较小的结构体成员写在前面是比较优秀的

    此外,结构体标准对齐值也可以自定义,具体操作可以参考这篇博客


    最后,下次写 (memset) 的参数就可以不用写算出占用的空间而不用 (sizeof) 啦!(丝毫没用)

  • 相关阅读:
    pip不是内部或外部命令也不是可运行的程序或批处理文件的问题
    动态规划 leetcode 343,279,91 & 639. Decode Ways,62,63,198
    动态规划 70.climbing Stairs ,120,64
    (双指针+链表) leetcode 19. Remove Nth Node from End of List,61. Rotate List,143. Reorder List,234. Palindrome Linked List
    建立链表的虚拟头结点 203 Remove Linked List Element,82,147,148,237
    链表 206 Reverse Linked List, 92,86, 328, 2, 445
    (数组,哈希表) 219.Contains Duplicate(2),217 Contain Duplicate, 220(3)
    重装系统
    java常用IO
    端口
  • 原文地址:https://www.cnblogs.com/zhwer/p/12294903.html
Copyright © 2020-2023  润新知