sizeof用法总结(个人感觉非常好的一篇文章)

本文详细解析了 C++ 中 sizeof 运算符的使用方法,包括基本数据类型、指针变量、数组、结构体、类等多种情况下 sizeof 的表现,并探讨了不同对齐方式对结果的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

sizeof用法总结

  1. 基本数据类型的sizeof
    cout << sizeof(char) << endl; 结果是1
    cout << sizeof(int) << endl; 结果是4
    cout << sizeof(unsigned int) << endl; 结果是4
    cout << sizeof(long int) << endl; 结果是4
    cout << sizeof(short int ) << endl; 结果是2
    cout << sizeof(float) << endl; 结果是4
    cout << sizeof(double) << endl; 结果是8
  2. 指针变量的sizeof
    char *pc =”abc”;
    sizeof( pc ); // 结果为4
    sizeof(*pc); // 结果为1
    int *pi;
    sizeof( pi ); //结果为4
    sizeof(*pi); //结果为4
    char **ppc = &pc;
    sizeof( ppc ); // 结果为4
    sizeof( *ppc ); // 结果为4
    sizeof( **ppc ); // 结果为1
    void (*pf)();// 函数指针
    sizeof( pf );// 结果为4

  3. 数组的sizeof数组的sizeof值等于数组所占用的内存字节数,如:
    char a1[] = “abc”;
    int a2[3];
    sizeof( a1 ); // 结果为4,字符 末尾还存在一个NULL终止符
    sizeof( a2 ); // 结果为3*4=12(依赖于int)
    写到这里,提一问,下面的c3,c4值应该是多少呢
    void foo3(char a3[3])
    {
    int c3 = sizeof( a3 ); // c3 == 4
    }
    void foo4(char a4[])
    {
    int c4 = sizeof( a4 ); // c4 == 4
    }
    也许当你试图回答c4的值时已经意识到c3答错了,是的,c3!=3。这里函数参数a3已不再是数组类型,而是蜕变成指针,相当于char* a3,为什么仔细想想就不难明白,我们调用函数foo3时,程序会在栈上分配一个大小为3的数组吗不会!数组是“传址”的,调用者只需将实参的地址传递过去,所以a3自然为指针类型(char*),c3的值也就为4。

  4. 结构体的sizeof
    struct MyStruct
    {
    double dda1;
    char dda;
    int type
    };
    //结果为16,为上面的结构分配空间的时候,VC根据成员变量出现的顺序和对齐方式,先为第一个成员dda1分配空间,其起始地址跟结构的起始地址相同(刚好偏移量0刚好为sizeof(double)的倍数),该成员变量占用sizeof(double)=8个字节;接下来为第二个成员dda分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移量为8,是sizeof(char)的倍数,所以把dda存放在偏移量为8的地方满足对齐方式,该成员变量占用sizeof(char)=1个字节;接下来为第三个成员type分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移量为9,不是sizeof(int)=4的倍数,为了满足对齐方式对偏移量的约束问题,VC自动填充3个字节(这三个字节没有放什么东西),这时下一个可以分配的地址对于结构的起始地址的偏移量为12,刚好是sizeof(int)=4的倍数,所以把type存放在偏移量为12的地方,该成员变量占用sizeof(int)=4个字节;这时整个结构的成员变量已经都分配了空间,总的占用的空间大小为:8+1+3+4=16,刚好为结构的字节边界数(即结构中占用最大空间的类型所占用的字节数sizeof(double)=8)的倍数,所以没有空缺的字节需要填充。所以整个结构的大小为:sizeof(MyStruct)=8+1+3+4=16,其中有3个字节是VC自动填充的,没有放任何有意义的东西。
  5. 含位域结构体的sizeof
    示例1:
    struct BF1
    {
    char f1 : 3;
    char f2 : 4;
    char f3 : 5;
    };
    其内存布局为:
    |f1_|f2||f3||
    |||||||||||||||||
    0 3 7 8 1316
    位域类型为char,第1个字节仅能容纳下f1和f2,所以f2被压缩到第1个字节中,而f3只能从下一个字节开始。因此sizeof(BF1)的结果为2。

  6. 含有联合体的结构体的sizeof
    struct s1
    {
    char *ptr,ch; //有指针变成4+4
    union A //后面跟了A定义了一个类型,不占内存,而后面不跟A,是声明了结构体的一个成员,占内存,
    {
    short a,b;
    unsigned int c:2, d:1;
    };
    struct s1* next; //指针占4
    };//这样是8+4=12个字节
    struct s1
    {
    char *ptr,ch;
    union //联合体是结构体的成员,占内存,并且最大类型是unsigned int,占4
    {
    short a,b;
    unsigned int c:2, d:1;
    };
    struct s1* next;
    };//这样是8+4+4=16个字节

  7. 结构体体含有结构体的sizeof
    struct S1
    {
    char c;
    int i;
    };
    struct S3
    {
    char c1;
    S1 s;
    char c2;
    };
    cout << sizeof(S3); //S3=16
    S1的最宽简单成员的类型为int,S3在考虑最宽简单类型成员时是将S1“打散”看的,
    所以S3的最宽简单类型为int,这样,通过S3定义的变量,其存储空间首地址需要被4整
    除,整个sizeof(S3)的值也应该被4整除。
    c1的偏移量为0,s的偏移量呢这时s是一个整体,它作为结构体变量也满足前面三个
    准则,所以其大小为8,偏移量为4,c1与s之间便需要3个填充字节,而c2与s之间就不需
    要了,所以c2的偏移量为12,算上c2的大小为13,13是不能被4整除的,这样末尾还得补
    上3个填充字节。最后得到sizeof(S3)的值为16。

  8. 带有#pragma pack的sizeof
    它是用来调整结构体对齐方式的,不同编译器名称和用法略有不同,VC6中通过#pragma pack实现,也可以直接修改/Zp编译开关。#pragma pack的基本用法为:#pragma pack( n ),n为字节对齐
    数,其取值为1、2、4、8、16,默认是8,如果这个值比结构体成员的sizeof值小,那么该成员的偏移量应该以此值为准,即是说,结构体成员的偏移量应该取二者的最小值,
    再看实例:
    pragma pack(push) // 将当前pack设置压栈保存
    pragma pack(2)// 必须在结构体定义之前使用
    struct S1
    {
    char c;
    int i;
    };
    struct S3
    {
    char c1;
    S1 s;
    char c2
    };
    pragma pack(pop)// 恢复先前的pack设置
    计算sizeof(S1)时,min(2, sizeof(i))的值为2,所以i的偏移量为2,加上sizeof(i)
    等于6,能够被2整除,所以整个S1的大小为6。
    同样,对于sizeof(S3),s的偏移量为2,c2的偏移量为8,加上sizeof(c2)等于9,不能
    被2整除,添加一个填充字节,所以sizeof(S3)等于10。

  9. 空结构体的sizeof
    struct S5 { };
    sizeof( S5 ); // 结果为1

  10. 类的sizeof
    类的sizeof值等于类中成员变量所占用的内存字节数。如:


class A
{
public:
int b;
float c;
char d;
};

int main(void)
{
A object;
cout << “sizeof(object) is ” << sizeof(object) << endl;
return 0 ;
}


输出结果为12(我的机器上sizeof(float)值为4,字节对其前面已经讲过)。

不过需要注意的是,如果类中存在静态成员变量,结果又会是什么样子呢?


class A
{
public:
static int a;
int b;
float c;
char d;
};

int main()
{
A object;
cout << “sizeof(object) is ” << sizeof(object) << endl;
return 0 ;
}


16?不对。结果仍然是12.

因为在程序编译期间,就已经为static变量在静态存储区域分配了内存空间,并且这块内存在程序的整个运行期间都存在。

而每次声明了类A的一个对象的时候,为该对象在堆上,根据对象的大小分配内存。

如果类A中包含成员函数,那么又会是怎样的情况呢?看下面的例子


class A
{
public:
static int a;
int b;
float c;
char d;
int add(int x,int y)
{
return x+y;
}
};

int main()
{
A object;
cout << “sizeof(object) is ” << sizeof(object) << endl;
b = object.add(3,4);
cout << “sizeof(object) is ” << sizeof(object) << endl;
return 0 ;
}


结果仍为12。

因为只有非静态类成员变量在新生成一个object的时候才需要自己的副本。
所以每个非静态成员变量在生成新object需要内存,而function是不需要的。

### 关于音频流数据转储的技术方法 #### 使用 ALSA 实现音频流数据的捕获与保存 在嵌入式 Linux 下,alsa-lib 是一种常用的工具来实现音频流的数据捕获和保存功能。通过配置合适的参数,可以将实时采集到的声音数据存储为指定格式的文件[^1]。 以下是基于 ALSA 的简单录音程序示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <alsa/asoundlib.h> #define BUFFER_SIZE 4096 int main() { int err; snd_pcm_t *capture_handle; // PCM handle for capture snd_pcm_hw_params_t *hw_params; unsigned int rate = 44100; // Sample rate (Hz) unsigned int channels = 2; // Number of channels snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; // Audio sample format FILE *output_file = fopen("captured_audio.raw", "wb"); if ((err = snd_pcm_open(&capture_handle, "default", SND_PCM_STREAM_CAPTURE, 0)) < 0) { fprintf(stderr, "Cannot open audio device (%s)\n", snd_strerror(err)); exit(1); } if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) { fprintf(stderr, "Cannot allocate hardware parameter structure (%s)\n", snd_strerror(err)); exit(1); } if ((err = snd_pcm_hw_params_any(capture_handle, hw_params)) < 0) { fprintf(stderr, "Cannot initialize hardware parameter structure (%s)\n", snd_strerror(err)); exit(1); } if ((err = snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { fprintf(stderr, "Cannot set access type (%s)\n", snd_strerror(err)); exit(1); } if ((err = snd_pcm_hw_params_set_format(capture_handle, hw_params, format)) < 0) { fprintf(stderr, "Cannot set sample format (%s)\n", snd_strerror(err)); exit(1); } if ((err = snd_pcm_hw_params_set_rate_near(capture_handle, hw_params, &rate, NULL)) < 0) { fprintf(stderr, "Cannot set sample rate (%s)\n", snd_strerror(err)); exit(1); } if ((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params, channels)) < 0) { fprintf(stderr, "Cannot set channel count (%s)\n", snd_strerror(err)); exit(1); } if ((err = snd_pcm_hw_params(capture_handle, hw_params)) < 0) { fprintf(stderr, "Cannot set parameters (%s)\n", snd_strerror(err)); exit(1); } free(hw_params); char buffer[BUFFER_SIZE]; while (1) { err = snd_pcm_readi(capture_handle, buffer, BUFFER_SIZE / sizeof(short)); if (err < 0){ fprintf(stderr,"Read from audio interface failed (%s)\n",snd_strerror(err)); break; } fwrite(buffer,sizeof(char),BUFFER_SIZE,output_file); } fclose(output_file); snd_pcm_close(capture_handle); } ``` 此代码片段展示了如何利用 ALSA 进行简单的音频录制,并将其写入原始二进制文件 `captured_audio.raw` 中。 --- #### FFmpeg 处理 RTSP 流中的音频数据 FFmpeg 提供了一个强大的框架用于处理音视频流,包括从网络协议(如 RTSP)获取音频数据并保存为标准格式文件的功能。如果遇到无法正确保存音频的情况,通常是因为编译时未启用必要的解码器支持。重新编译 FFmpeg 并确保启用了相关选项即可解决问题[^2]。 下面是一个命令行例子,展示如何使用 FFmpeg 将来自 RTSP 流的音频提取出来并保存成 WAV 文件: ```bash ffmpeg -i rtsp://your_rtsp_stream_url -vn -acodec pcm_s16le output.wav ``` 该命令会忽略视频部分 (`-vn`) 只保留音频轨道,并采用无压缩编码方式(`pcm_s16le`) 输出至目标文件 `output.wav`。 --- #### 其他可能涉及的方法和技术 除了上述两种主流技术外,在某些特定场景下还可以考虑其他方案比如 PulseAudio 或 PortAudio 等跨平台库来进行更灵活的操作;或者借助 GStreamer 构建复杂的多媒体流水线完成同样的任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值