首页 > 编程语言 >C++ sizeof 杂谈

C++ sizeof 杂谈

时间:2023-09-15 16:24:34浏览次数:45  
标签:struct int 杂谈 long C++ printf sizeof lld

原来 sizeof 是一个特殊的,运算优先级很高的一种运算符?之前一直都不知道。

参考博客:

c++中sizeof()的用法介绍

C++ 学习杂谈:sizeof(string)到底是多少?

优先级

作为一个运算符,sizeof 自然也是有优先级的,它在 C++ 中优先级为 \(3\),也就是除了作用域解析运算符和诸如括号的操作符,它优先级基本上是最高的,和一般的运算符不同,它的运算是从右向左进行结合的。

运算逻辑

看一下 sizeof 在 msdn 上的定义:

The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type (including aggregate types). This keyword returns a value of type size_t.

其作用就是返回一个对象或者类型所占的内存字节数,注意,sizeof 返回值是 unsigned long long int

然而一定记住 sizeof 不是一个函数,可以不加括号,比起操作运算符更像是一个特殊的宏,在编译阶段进行求值,为什么这么说?看下文吧。

运算

函数

我们都知道,sizeof 其实是可以对一个函数调用求值的。其结果是函数返回值类型的大小,函数并不会被调用

对函数求值的形式:`sizeof(函数名(实参表))``

注意:
1)不可以对返回值类型为空的函数求值。

2)不可以对函数名求值。

3)对有参数的函数,在用 sizeof 时,须写上实参表。

exp.

#include<bits/stdc++.h>
using namespace std;
unsigned long long int zyx(){
    return 0;
}
int cnt;
void sbzyx(){
    return;
}
int nbest(){
    cnt++;
    return 1;
}
int main(){
    printf("%lld\n",sizeof zyx());
    //输出 8,等价于 sizeof unsigned long long int
    //printf("%lld\n",sizeof sbzyx()); 我这里好像不会报错,输出了个 1,但是会 warning
    //printf("%lld\n",sizeof zyx);报错
    printf("%lld\n",sizeof nbest());
    //输出 4,等价于 sizeof int
    printf("%d\n",cnt);
    //输出 0,证明并没有调用函数
    return 0;
}

基本类型

直接返回类型所占字节,输出对应类型的变量的 sizeof 也一样。

结构体

我也不知道结构体会有字节对齐的问题。

可供参考博客:C/C++ struct字节对齐那些事儿

具体原因上网查吧,我这里展示个代码你们就懂了。

#include<bits/stdc++.h>
using namespace std;
struct node{
    int p;
    long long k;
    bool w;
};
struct node1{
    int p[53];
    long long k;
    bool w;
};
struct node2{
    int p[54];
    long long k;
    bool w;
};
struct zyx{
    int p;
};
struct nb{

};
int main(){
    printf("%lld %lld %lld\n",sizeof(zyx),sizeof(node),sizeof(nb));
    //第一个不出意料的输出 4
    //第二个输出24
    //第三个输出 1
    printf("%lld %lld",sizeof(node1),sizeof(node2));
    //没想到吧,两个都是输出 232,因为两个 int 直接对齐了,但是最后单独的一个 int 为了和 long long 对齐,也会被改成 8。
    return 0;
}

有趣的小知识:
C/C++不允许对struct成员进行重排序,即成员的内存排列顺序一定是定义顺序。

所以这会导致一个问题:

#include<bits/stdc++.h>
using namespace std;
struct node1{
    int a;
    bool b;
    long long c;
};
struct node2{
    int a;
    long long c;
    bool b;
};
int main(){
    cout<<sizeof(node1)<<endl;
    //输出16,因为int 和 bool 合并之后再对齐
    cout<<sizeof(node2);
    //输出24,int 和bool 分别对齐
    return 0;
}

看似相同的代码内存占用却不一样(当然数据大的话其实看不出来)。

联合体union

结构体在内存组织上是顺序式的,联合体则是重叠式,各成员共享一段内存。所以整个联合体的 sizeof 也就是每个成员 sizeof 的最大值。

#include<bits/stdc++.h>
using namespace std;
union poper{
    int k;
    long long p;
    bool x;
    int w[6];
    char ppp[8];
};
union po{
    int k;
    long long p;
    bool x;
    //int w[6];
    //char ppp[8];
};
int main(){
    printf("%lld %lld",sizeof(poper),sizeof(po));
    //第一个最长的是 w[6] 为 4*6=24,输出24
    //第二个最长的是 long long ,输出8
    return 0;
}

数组

数组的 sizeof 值等于数组所占用的内存字节数。

  • 当字符数组表示字符串时,其 sizeof 值将 /0 计算进去。
  • 当数组为形参时,其sizeof值相当于指针的sizeof值。
#include<bits/stdc++.h>
using namespace std;
int poper[82];
char po[18];
char zyx[]="sbzyx";
void yqt(char a[]){
    cout<<sizeof(a)<<endl;
}
void yqtsb(char a[18]){
    cout<<sizeof(a)<<endl;
}
int main(){
    printf("%lld %lld %lld\n",sizeof(poper),sizeof(po),sizeof(zyx));
    //输出 328 18 6
    yqt(po);
    //输出 8,即指针大小
    yqtsb(po);
    //输出 8,同上
    return 0;
}

指针

指针是用来记录另一个对象的地址,所以指针的内存大小当然就等于计算机内部地址总线的宽度。

指针变量的 sizeof 值与指针所指的对象没有任何关系,同一台计算机输出的结果一定一样。

动态空间

比如 string,vector 等动态空间,对它们用 sizeof 的返回值通常是固定的,与长度无关。但是这并不意味着它们的空间就是这么大。

#include<bits/stdc++.h>
using namespace std;
string a="abcadfasfsddxgsdfgf";
basic_string<int>poww;
basic_string<pair<int,int> >fc; 
basic_string<char>fwc="1"; 
vector<pair<int,int> >f(1965);
pair<int,long long> w;
int main(){
    printf("%lld %lld %lld\n",sizeof a,sizeof f,sizeof w);
    //32 24 16
    printf("%lld %lld %lld %lld\n",sizeof(fc),sizeof(fwc),sizeof(poww),sizeof(string));
    //32 32 32 32
    return 0;
}

奇怪的运算符

所以我们可以回答上面的问题了,为什么说 sizeof 很奇怪呢?正常的运算符都是会运行内部的运算的,但是 sizeof 不会(不会运算函数,不会运行赋值操作等)。

#include<bits/stdc++.h>
using namespace std;
int a;
int main(){
    cout<<sizeof(a=3)<<endl;
    //4
    cout<<a<<endl;
    //0
    cout<<sizeof(++a)<<endl;
    //4
    cout<<a<<endl;
    //0
    return 0;
}

小结

为了初赛,算是搞懂了这个奇怪的东西,去研究 union 了~

标签:struct,int,杂谈,long,C++,printf,sizeof,lld
From: https://www.cnblogs.com/NBest/p/17705273.html

相关文章

  • 设计模式 C++
    (设计模式)(李建忠C++)23种设计模式组件协作模板方法父类中定义组件(函数)的调用流程,每个组件使用虚函数进行实现,然后子类中可以重写父类中虚函数的实现。如果我们发现一个算法的组件(函数)的调用流程都是一样的,但是步骤中的各个组件的实现可能有所差异,此时会使用模板方法。【......
  • C++中STL用法汇总
    1什么是STL?STL(StandardTemplateLibrary),即标准模板库,是一个具有工业强度的,高效的C++程序库。它被容纳于C++标准程序库(C++StandardLibrary)中,是ANSI/ISOC++标准中最新的也是极具革命性的一部分。该库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法。为广大C++程......
  • Qt/C++音视频开发53-本地摄像头推流/桌面推流/文件推流/监控推流等
    一、前言编写这个推流程序,最开始设计的时候是用视频文件推流,后面陆续增加了监控摄像头推流(其实就是rtsp视频流)、网络电台和视频推流(一般是rtmp或者http开头m3u8结尾的视频流)、本地摄像头推流(本地USB摄像头或者笔记本自带摄像头等)、桌面推流(将当前运行环境的系统桌面抓拍推流)。按......
  • C++完美转发为什么必须要有std::forward?
    先看一种情况,它的输出结果是什么?#include<iostream>usingnamespacestd;voidF(constint&a){cout<<"int:"<<a<<endl;}voidF(int&&a){cout<<"int&&:"<<a<<endl......
  • C++-类和对象(3)
    今天,继续和大家分享与类和对象相关的知识,本次文章的内容主要分享拷贝构造函数相关的知识。在学习拷贝构造函数之前,我们先对构造函数和析构函数进行一个总结回顾,在接这往下。构造函数和析构函数的总结回顾不论是构造函数还析构函数,我们只需要抓它们的特性,就可以很好的使用它们了。构......
  • C++下标运算符详解
    C++规定,下标运算符[]必须以成员函数的形式进行重载。该重载函数在类中的声明格式如下:返回值类型&operator[](参数);const返回值类型&operator[](参数)const;使用第一种声明方式,[]不仅可以访问元素,还可以修改元素。使用第二种声明方式,[]只能访问而不能修改元素。在实......
  • C++ STL
    Dev-C++可在工具->编译选项->代码生成/优化->代码生成->语言标准中选择“ISOC++11”或“GNUC++11”来支持C++11的新特性(蓝Dev还不支持C++14)不声明下,区间均为左闭右开区间,typename表示一个数据类型而不是C++的关键字。Containter(容器)vectorvector<t......
  • C++字符串
      1,2这个形式的字符串数组,就和普通数组一样,定义后面的大括号,里面装着每个具体的值,然后3,4直接表示出来,然后其实直接3就OK了,4可能是为了方便看。   字符串数组输入部分1.这个。。先把字符串数组定义好,然后使用cin直接输入进去2.如果想要读入包含空格键之类字符串的话......
  • C++11之智能指针(万字长文详解)
    C++11之智能指针为什么需要智能指针#include<iostream>usingnamespacestd;intdiv(){inta,b;cin>>a>>b;if(b==0)throwinvalid_argument("除0错误");returna/b;}voidFunc(){//1、如果p1这......
  • C++基础语言作用
    C++跟C语言是相关联的。页面排序:includeincludeusingnamespacestd;intmain(){...return0;}cin作为输入,类似于C语言的scanf。输入时添加>>a代表输入a值。可以接收一行内多个数据输入,不可以接收多行数据。cout作为输出,类似C语言的printf。cout默认是在一行内输出,如......