| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> GCC AVR(Atmel Studio+ AVR Studio)如何在程序存储器(flash)空间存放字符串常量和使用字符串常量 -> 正文阅读 |
|
[C++知识库]GCC AVR(Atmel Studio+ AVR Studio)如何在程序存储器(flash)空间存放字符串常量和使用字符串常量 |
目录 二、如何将字符串变量定义到program memory(flash) 一、program memory和data memory? ? ? ? GCC AVR(Atmel Studio+ AVR Studio)默认将变量(包含普通变量、数组和字符串)定义在data memory,这个需要特别注意。 ? ? ? ? 如果程序中定义有大量的常量,在定义时,一定要在头部写上PROGMEM,还要添加头文件#include <avr/pgmspace.h>,这样,定义的常量就保存在program memory(flash)中了。否则,系统就会将变量定义到data memory区,编译时由于data memory仅有4k而会出现内存溢出的现象。 二、如何将字符串变量定义到program memory(flash)? ? ? ? 第一步:必须包含头文件:#include <avr/pgmspace.h>
? ? ? ? 第二步:用关键字PROGMEM定义字符串常量
三、如何读取字符串变量? ? ? ? 当data memory区的变量去读取program memory区的数据时,需要用库函数pgm_read_byte()进行读取,下面我们编写一个入口参数为字符串常量的函数,将入口的字符串常量发送到串口1,需要用到系统提供的函数pgm_read_byte()。
四、PSTR()? ? ? ? AVR提供了一个宏 PSTR(),它在头文件pgmspace.h中,它可以用于将字符串定义到program memory区(flash)。宏 PSTR()的具体定义参见下图。 ? ? ? ? ?上面的程序代码可以不定义PROGMEM const char flash_string[]= "Hello World.";? 而是可以直接用宏 PSTR()将字符串定义到program memory区(flash),改造后的程序如下:
五、使用strcpy()函数将字符串常量拷贝字符串缓冲区会占用大量的data memory区空间;使用strcpy_P()函数将字符串常量拷贝到字符串缓冲区仅仅占用program memory区(flash)空间,不会占用data memory区空间。1、使用strcpy()函数拷贝字符串前,先在data memory空间定义了一个字符串缓冲区char HMI_string[255],编译程序后发现data memory空间占用了2362个字节。 ?2、现在我们用库函数strcpy()编写一段程序,将字符串常量 "I am C++"拷贝到字符串缓冲区HMI_string,观察是否会占用data memory区空间。 ? ? ? ? 程序代码参见下图,编译程序后发现data memory空间目前占用了2370个字节(之前为2362个字节)。 ? ? ? ? 怎么只是在程序中调用了strcpy(HMI_string , "I am C++") ,data memory空间就多占用了8个字节呢?? ? ? ??3、现在我们用库函数strcpy()再编写一段程序,将字符串常量 "I am C#"拷贝到字符串缓冲区HMI_string,观察是否会继续占用data memory区空间。 ? ? ? ??程序代码参见下图,编译程序后发现data memory空间目前占用了2378个字节,又比之前多占用了8个字节(之前占用了2370个字节)。 ? ? ? ? 我们发现一个规律:(1)、只要调用strcpy(HMI_string , "I am C++"),编译器发现第二个入口参数是普通的字符串"I am C++",就会在data memory空间申请8个字节的空间。(2)、只要调用strcpy(HMI_string , "I am C#"),编译器发现第二个入口参数是普通的字符串"I am C#",就会在data memory空间申请8个字节的空间。? ? ? ? ?4、如何将一串字符串常量拷贝到字符串缓冲区,而且还可以确保第二个入口参数不占用data memory空间呢? ? ? ??strcpy()函数是GCC AVR的头文件string.h中的函数,要想将一串字符串常量拷贝到字符串缓冲区,而且字符串拷贝函数的入口参数还不占用data memory空间,就必须要使用头文件pgmspace.h中的库函数strcpy_P,库函数strcpy_P的原型如下:
? ? ? ? 头文件pgmspace.h中的库函数与头文件string.h中的库函数的区别是: ? ? ? ? (1)、pgmspace.h中的库函数比头文件string.h中的库函数多了一个后缀? _P。 ? ? ? ? (2)、char *strcpy_P(char *, const char *)? ?第二个参数是程序存储器program memory区(flash)。 ? ? ? ? (3)、主程序调用strcpy_P(HMI_string , PSTR("I am C++"));时,第二个参数不会占用data memory空间。
5、验证 ? ? ? ? (1)、程序中添加 strcpy_P(HMI_string , PSTR("I am C++")); ,程序编译程序后data memory空间仍然是2362字节,可见使用头文件pgmspace.h中的库函数 strcpy_P(), 第二个参数PSTR("I am C++")不会增加data memory空间。? ? ?? ? ? ? (2)、程序中再添加 strcpy_P(HMI_string , PSTR("I am C#")); ,程序编译程序后data memory空间仍然是2362字节,可见使用头文件pgmspace.h中的库函数 strcpy_P(), 第二个参数PSTR("I am C#")不会增加data memory空间。? ? ?六、使用sprintf()函数将字符串常量打印到字符串缓冲区会占用大量的data memory区空间;使用sprintf_P()函数将字符串常量打印到字符串缓冲区仅仅占用program memory区(flash)空间,不会占用data memory区空间。1、使用sprintf()函数打印字符串前,编译程序后发现data memory空间占用了2362个字节。 ?2、现在我们用库函数sprintf()编写一段程序,将字符串常量 "I am C++"和数值1275混合打印到字符串缓冲区HMI_string,观察是否会占用data memory区空间。 ? ? ? ? 程序代码参见下图,编译程序后发现data memory空间目前占用了2372个字节(之前为2362个字节)。 ? ? ? ? 怎么只是在程序中调用了sprintf(HMI_string , "I am C++%d" , 1278) ,data memory空间就多占用了10个字节呢?? ? ? ?? ? ? ?我们发现一个规律:(1)、只要调用sprintf(HMI_string , "I am C++%d" , 1278) ,编译器发现第二个入口参数是普通的字符串"I am C++",就会在data memory空间申请10个字节的空间。 ?3、如何将一串字符串常量和数值混合打印到字符串缓冲区,而且还可以确保第二个入口参数不占用data memory空间呢? ? ? ??sprintf()函数是GCC AVR的头文件string.h中的函数,要想将一串字符串常量和数值混合打印到字符串缓冲区,而且字符串打印函数的入口参数还不占用data memory空间,就必须要使用头文件pgmspace.h中的库函数sprintf_P,库函数sprintf_P的原型如下:
? ? 头文件pgmspace.h中的库函数与头文件string.h中的库函数的区别是: ? ? ? ? (1)、pgmspace.h中的库函数比头文件string.h中的库函数多了一个后缀? _P。 ? ? ? ? (2)、 int?? ?sprintf_P(char *__s, const char *__fmt, ...);?第二个参数是程序存储器program memory区(flash)。 ? ? ? ? (3)、主程序调用sprintf(HMI_string , "I am C++%d" , 1278)时,第二个参数不会占用data memory空间。
4、验证 ? ? ? ? (1)、程序中添加 sprintf_P(HMI_string , PSTR("I am C++%d") , 1278); ,程序编译程序后data memory空间仍然是2362字节,可见使用头文件pgmspace.h中的库函数 sprintf_P(), 第二个参数PSTR("I am C++%d")不会增加data memory空间。? ? ? 七、总结1、要想定义字符串常量到program memory区,首先要添加头文件#include <avr/pgmspace.h>, 2、然后用关键字PROGMEM定义字符串常量,例如:PROGMEM const char flash_string[]= "Hello World."; 3、也可以宏定义PSTR()直接在用户函数的入口参数上进行限制,例如:HMISendString_const(PSTR("Hello World.")); 4、要想将字符串常量拷贝字符串缓冲区而不占用data memory区空间,必须要使用头文件pgmspace.h中的strcpy_P(),而不能使用头文件string.h中的strcpy()。而且strcpy_P()的第二个入口参数必须要用宏PSTR()进行限定,例如:strcpy_P(HMI_string , PSTR("I am C++")); 5、要想将字符串常量和数值混合打印到字符串缓冲区而不占用data memory区空间,必须要使用头文件pgmspace.h中的sprintf_P(),而不能使用头文件string.h中的sprintf()。而且sprintf_P()的第二个入口参数必须要用宏PSTR()进行限定,例如:sprintf_P(HMI_string , PSTR("I am C++%d") , 1278); |
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 | -2025/1/11 6:30:46- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |