STM32嵌入式:printf函数不定参数解析

需积分: 6 0 下载量 83 浏览量 更新于2024-09-06 收藏 760KB PDF 举报
"这篇文档详细介绍了在单片机和嵌入式系统中,特别是基于STM32-F3/F4/F7/H7系列芯片的环境里,如何处理`printf`函数的不定参数。文档强调了不定参数必须位于函数参数列表的最后,并解释了参数传递的机制,特别是ARM架构下的参数传递规则。" 在嵌入式开发,尤其是单片机编程中,`printf`函数是一种常用的格式化输出函数,其特点是可以接受任意数量和类型的参数。文档指出,这种不定参数的列表必须遵循一个规定:它们必须是整个函数参数列表的最后部分。这是为了方便编译器和运行时系统处理这些参数。 函数调用时,参数通常是通过堆栈来传递的。在51系列单片机中,由于硬件不支持真正的堆栈,所以会模拟一个堆栈,而ARM架构的处理器则拥有实际的堆栈,并且无论哪种情况,堆栈都是向下生长的,即新的数据被压入更低的内存地址。这样设计的好处是,函数在访问参数时可以按照固定的顺序从低地址向高地址读取。 在ARM架构中,参数传递规则有所不同。当参数数量小于或等于4个时,参数会依次存放在寄存器r0、r1、r2和r3中。如果参数超过4个,前四个参数仍然放在这些寄存器中,剩下的参数则入栈,但入栈顺序是从右到左,即最后一个参数先入栈。例如,在给定的代码片段中,我们可以看到在调用`testStack`函数时,参数依次被存储在r0到r3中,然后多余的参数被放入堆栈。 示例代码展示了当传递12个整数参数时,ARM处理器如何处理这些参数。首先,前四个参数被分别赋值给r0到r3,然后r3、r2和r1的值被依次存储到堆栈中,最后r0的值也被存入堆栈。这样的顺序确保了在函数内部可以通过堆栈访问所有参数,而不会混淆。 这个过程对于理解如何在嵌入式环境中正确使用`printf`等可变参数函数至关重要,因为这直接影响到程序的正确性和效率。正确地理解和应用这些规则,能帮助开发者编写出更高效、更可靠的代码,特别是在资源有限的单片机环境中。

void basicSettings(struct Student* student, struct Course courses[], int* numCourses) { int choose; printf("\n--------基本设置--------\n"); printf("\n--------1.添加学生信息--------\n"); printf("\n--------2.添加老师信息--------\n"); printf("\n--------3.修改密码--------\n"); printf("\n--------4.返回--------\n"); printf("请输入您的选择:\n"); scanf("%d", &choose); if(choose==1){ printf("\n"); printf("请输入班级:"); scanf("%s", student->className); printf("请输入学号:"); scanf("%s", student->id); printf("请输入姓名:"); scanf("%s", student->name); } if(choose==2) { printf("\n"); printf("请输入课程数:"); scanf("%d", numCourses); printf("请输入每门课程的名称和教师名字:\n"); for (int i = 0; i < *numCourses; i++) { printf("第%d门课程:", i + 1); scanf("%s %s", courses[i].name, courses[i].teacher); } } if(choose==3) { void changePassword(struct User* user) { printf("\n--------修改密码--------\n"); printf("请输入旧密码:"); char oldpassword[MAX_NAME_LEN]; scanf("%s", oldpassword); if (strcmp(oldpassword, user->password) != 0) { printf("密码错误,修改失败!\n"); return; } printf("请输入新密码:"); scanf("%s", user->password); printf("密码已修改!\n"); } changePassword(user_p); } FILE* fp = fopen("student.dat", "wb"); if (fp == NULL) { printf("无法打开文件!\n"); return; } fwrite(student, sizeof(struct Student), 1, fp); fclose(fp); fp = fopen("courses.dat", "wb"); if (fp == NULL) { printf("无法打开文件!\n"); return; } fwrite(courses, sizeof(struct Course), *numCourses, fp); fclose(fp); printf("设置已保存!\n"); } 修改代码

117 浏览量

void welcome() { printf("**********欢迎使用管理系统*************\n"); //以不同的角色进行登录系统 printf("1.管理员身份登录\n"); printf("2.普通用户学生登录\n"); printf("3.退出\n"); printf("******************************************\n"); } //管理员的菜单界面 void mangeview() { printf("**********欢迎管理员登录********\n"); printf("-----------------1.注册学生信息------------------\n"); printf("-----------------2.输出学生信息------------------\n"); printf("-----------------3.删除学生信息------------------\n"); printf("-----------------4.修改学生信息------------------\n"); printf("-----------------5.查询学生信息------------------\n"); printf("-----------------6.学生请假和补卡------------------\n"); printf("-----------------7.排序(姓名、学号、打卡次数)--\n"); printf("-----------------8.考勤数据统计------------------\n"); printf("-----------------9.返回------o( ̄ヘ ̄o#)----\n"); //........ printf("********************************\n"); } //普通用户界面 //普通用户界面提示 void comuser(){ printf("************欢迎学生登录************\n"); printf("-----------------1.录入学生信息------------------\n"); printf("-----------------2.输出学生信息------------------\n"); printf("-----------------3.查询学生信息------------------\n"); printf("-----------------4.排序(姓名、学号、打卡次数)--\n"); printf("-----------------5.学生请假和补卡------------------\n"); printf("-----------------6.返回------o( ̄ヘ ̄o#)----\n"); printf("********************************************\n"); } 这个代码怎么描述,运用了什么函数

138 浏览量
103 浏览量