Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
C语言
经验
sizeof
C语言知识点:sizeof的使用与注意事项
发布于 2021-08-08 15:05:44 浏览:1151
订阅该版
[tocm] [RT-Thread 入门学习笔记 - 目录](https://club.rt-thread.org/ask/article/3420.html) ## 前言 - `sizeof`在C语言中比较的常见,需要熟悉正确的使用 - 需要熟悉基本数据类型、数组、指针、结构体的字节大小 - 防止计算出错,引起内存的越界访问。 ## 实例与分析 - 嵌入式软件开发中,会经常遇到缓冲区溢出、内存溢出、栈溢出、内存写穿等问题 - 需要实时调试验证自己的内存操作,无论是静态还是动态的内存,地址的计算、指针的计算,是否正确。 ```c #include
#include
#define TEST_BUF_SIZE 32 struct test_msg { rt_uint32_t id; rt_uint32_t cmd; rt_uint32_t value; rt_uint8_t *data; rt_uint32_t data_len; }; void dump_struct_size(void) { rt_kprintf("sizeof(struct rt_thread)=%d\n", sizeof(struct rt_thread)); rt_kprintf("sizeof(struct rt_memheap)=%d\n", sizeof(struct rt_memheap)); rt_kprintf("sizeof(struct rt_device)=%d\n", sizeof(struct rt_device)); rt_kprintf("sizeof(struct rt_messagequeue)=%d\n", sizeof(struct rt_messagequeue)); rt_kprintf("sizeof(struct rt_mempool)=%d\n", sizeof(struct rt_mempool)); rt_kprintf("sizeof(struct rt_mailbox)=%d\n", sizeof(struct rt_mailbox)); rt_kprintf("sizeof(struct rt_timer)=%d\n", sizeof(struct rt_timer)); rt_kprintf("sizeof(struct rt_mutex)=%d\n", sizeof(struct rt_mutex)); rt_kprintf("sizeof(struct rt_semaphore)=%d\n", sizeof(struct rt_semaphore)); rt_kprintf("sizeof(struct rt_event)=%d\n", sizeof(struct rt_event)); rt_kprintf("sizeof(struct rt_memheap_item)=%d\n", sizeof(struct rt_memheap_item)); rt_kprintf("sizeof(struct rt_ipc_object)=%d\n", sizeof(struct rt_ipc_object)); rt_kprintf("sizeof(struct rt_object)=%d\n", sizeof(struct rt_object)); rt_kprintf("sizeof(struct rt_object_information)=%d\n", sizeof(struct rt_object_information)); rt_kprintf("sizeof(rt_list_t)=%d\n", sizeof(rt_list_t)); rt_kprintf("sizeof(rt_mq_t)=%d\n", sizeof(rt_mq_t)); rt_kprintf("sizeof(rt_bool_t)=%d\n", sizeof(rt_bool_t)); rt_kprintf("sizeof(rt_slist_t)=%d\n", sizeof(rt_slist_t)); rt_kprintf("sizeof(rt_timer_t)=%d\n", sizeof(rt_timer_t)); rt_kprintf("sizeof(rt_thread_t)=%d\n", sizeof(rt_thread_t)); rt_kprintf("sizeof(rt_sem_t)=%d\n", sizeof(rt_sem_t)); rt_kprintf("sizeof(rt_mutex_t)=%d\n", sizeof(rt_mutex_t)); rt_kprintf("sizeof(rt_event_t)=%d\n", sizeof(rt_event_t)); rt_kprintf("sizeof(rt_mailbox_t)=%d\n", sizeof(rt_mailbox_t)); rt_kprintf("sizeof(rt_device_t)=%d\n", sizeof(rt_device_t)); } void sizeof_test_03(void) { struct test_msg msg_01 = { 0 }; struct test_msg *msg_ptr = &msg_01; rt_uint8_t *buf_char = RT_NULL; rt_uint16_t *buf_int16 = RT_NULL; rt_uint32_t *buf_int32 = RT_NULL; rt_thread_t thread_ptr = RT_NULL; rt_kprintf("sizeof(msg_01)=%d\n", sizeof(msg_01)); rt_kprintf("sizeof(msg_ptr)=%d\n", sizeof(msg_ptr)); rt_kprintf("sizeof(struct test_msg)=%d\n", sizeof(struct test_msg)); rt_kprintf("msg_ptr=%08x\n", msg_ptr); rt_kprintf("msg_ptr+1 = %08x\n", (msg_ptr+1)); rt_kprintf("sizeof(buf_char)=%d\n", sizeof(buf_char)); rt_kprintf("buf_char addr=%08x\n", buf_char); rt_kprintf("buf_char+1=%08x\n", buf_char + 1); rt_kprintf("sizeof(buf_int16)=%d\n", sizeof(buf_int16)); rt_kprintf("buf_int16 addr=%08x\n", buf_int16); rt_kprintf("buf_int16+1=%08x\n", buf_int16 + 1); rt_kprintf("sizeof(buf_int32)=%d\n", sizeof(buf_int32)); rt_kprintf("buf_int32 addr=%08x\n", buf_int32); rt_kprintf("buf_int32+1=%08x\n", buf_int32 + 1); rt_kprintf("sizeof(thread_ptr)=%d\n", sizeof(thread_ptr)); rt_kprintf("thread_ptr addr=%08x\n", thread_ptr); rt_kprintf("thread_ptr+1=%08x\n", thread_ptr + 1); } static rt_uint8_t test_buf[TEST_BUF_SIZE] = { 's', 'i', 'z', 'e', 'o', 'f' }; /* 注意指针的sizeof 在32位的MCU上为 4(字节数) */ void input_buffer_param(rt_uint8_t *buf) { rt_kprintf("sizeof(buf) = %d\n", sizeof(buf)); } /* 传的参数是数组,只会把数组的地址传入,不包括数组的大小【空间】 */ void input_array_param(rt_uint8_t buf[]) { rt_kprintf("sizeof(buf) = %d\n", sizeof(buf)); /* warning! */ rt_kprintf("strlen(buf) = %d\n", strlen((char *)buf)); } void sizeof_test_01(rt_uint8_t *buf) { rt_kprintf("sizeof(test_buf)=%d\n", sizeof(test_buf)); input_buffer_param(test_buf); } void sizeof_test_02(void) { input_array_param(test_buf); } MSH_CMD_EXPORT(sizeof_test_01, sizeof_test 01); MSH_CMD_EXPORT(sizeof_test_02, sizeof_test 02); MSH_CMD_EXPORT(sizeof_test_03, sizeof_test_03); MSH_CMD_EXPORT(dump_struct_size, dump_struct_size); ``` ## 运行数据与总结 ```c msh >sizeof_test_01 sizeof(test_buf)=32 sizeof(buf) = 4 ``` - `sizeof`数组名,得到的是整个数组的大小,如这里定义的是32字节的数组`test_buf`,sizeof得出32。 - `sizeof`指针,得到的是指针的大小:4(32位MCU)。 - 【小常识】数组作为函数的入参,传的是地址,而不是整个数组。 ```c msh >sizeof_test_02 sizeof(buf) = 4 strlen(buf) = 6 ``` - 函数的数组入参是指针,所以sizeof为4(32位MCU) - strlen可以获取字符数组内容的长度(遇到字符0x00结束),无法获取整个数组的占用大小 ```c msh >sizeof_test_03 sizeof(msg_01)=20 sizeof(msg_ptr)=4 sizeof(struct test_msg)=20 msg_ptr=200028a4 msg_ptr+1 = 200028b8 sizeof(buf_char)=4 buf_char addr=00000000 buf_char+1=00000001 sizeof(buf_int16)=4 buf_int16 addr=00000000 buf_int16+1=00000002 sizeof(buf_int32)=4 buf_int32 addr=00000000 buf_int32+1=00000004 sizeof(thread_ptr)=4 thread_ptr addr=00000000 thread_ptr+1=00000080 ``` - 不同的数据类型,`sizeof`获取的大小不同。 - `sizeof`结构体,得到的是整个结构体占用内存的大小 - `sizeof`结构体指针,获取的是4(32位MCU)。 - `sizeof`可以是某类型的变量,也可以是某类型本身。 - 某类型的指针变量的`+1`,不是简单的地址值的`+1`,而是增加了数据类型的大小。如一个大小为20字节(0x14),指针变量的+1,地址增加了:20字节(0x14),计算方法:(`0x200028b8 - 0x200028a4 = 0x14`) - 如rt_thread 这个结构体,大小为:128字节(0x80),这个类型的指针变量`+1`后,地址增加了0x80。 ```c msh >dump_struct_size sizeof(struct rt_thread)=128 sizeof(struct rt_memheap)=100 sizeof(struct rt_device)=64 sizeof(struct rt_messagequeue)=60 sizeof(struct rt_mempool)=52 sizeof(struct rt_mailbox)=48 sizeof(struct rt_timer)=44 sizeof(struct rt_mutex)=36 sizeof(struct rt_semaphore)=32 sizeof(struct rt_event)=32 sizeof(struct rt_memheap_item)=24 sizeof(struct rt_ipc_object)=28 sizeof(struct rt_object)=20 sizeof(struct rt_object_information)=16 sizeof(rt_list_t)=8 sizeof(rt_mq_t)=4 sizeof(rt_bool_t)=4 sizeof(rt_slist_t)=4 sizeof(rt_timer_t)=4 sizeof(rt_thread_t)=4 sizeof(rt_sem_t)=4 sizeof(rt_mutex_t)=4 sizeof(rt_event_t)=4 sizeof(rt_mailbox_t)=4 sizeof(rt_device_t)=4 ``` - 这个函数打印了`rt-thread`中的大部分内部结构体的大小,注意线程栈不要设置太小,造成程序无法正常的工作。 - 指针变量的`sizeof`一直都是4(32位MCU) ## 错误示例 ```c void uart_printf(v_list fmt) { HAL_UART_Transmit(&huart1, (uint8_t *)fmt, sizeof(fmt), 0xFFFF); } ``` - 问题分析:获取字符内容的长度,可以使用`strlen`,`sizeof`指针长度只有4字节(32位MCU), 造成输出长度不对。 ```c #define TEST_BUF_SIZE 32 rt_uint32_t test_buf[TEST_BUF_SIZE]; void test_buf_init(void) { memset(test_buf, 0, sizeof(test_buf)*TEST_BUF_SIZE); } ``` - 问题分析:`sizeof`一个数组,无论数组成员的类型是什么,已经获取了整个数组的大小,所以不用再乘上`TEST_BUF_SIZE`,否则造成缓冲区溢出,清零了其临近内存空间数据,引起异常。 ## 小结 - 注意获取数据类型长度:`sizeof`的正确使用 - 如果需要获取字符数组的内容的长度,可以使用`strlen` - 错误的使用`sizeof`,会造成缓冲区溢出或长度计算错误,引起程序工作异常。
2
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
张世争
学以致用
文章
131
回答
809
被采纳
175
关注TA
发私信
相关文章
1
RT-Thread内存和字符串相关函数与C语言自带的内存和字符串相关函数冲突问题
2
嵌入式RT-thread中初始化线程函数中(void *)entry的意义何在
3
cJSON parse 失败,请问怎么解决?
4
请教一个C语言顺序表的问题,不知道有没有大佬帮吗解答
5
小白请教,关于头文件引用,、、哪些场景需要引用它们?
6
使用中断有warn。。。。。。。。。。。
7
局部变量位置被编译器改写
8
RTthread 两个例程结合在一起会出现incompatible type for argument 2 of 'led_matrix_set_color'
9
有没有在单片机编程使用goto语句的?
10
请问如何读取另一个c文件中的温湿度数据啊
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
中断
编译报错
Debug
SFUD
rt_mq_消息队列_msg_queue
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
a1012112796
10
个答案
1
次被采纳
踩姑娘的小蘑菇
4
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
Ryan_CW
4
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
YZRD
2
篇文章
5
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部