GCC背后的故事&C程序常量变量的地址分配

一. 学习并掌握可执行程序的编译、组装过程。学习任务如下:阅读、理解和学习材料“用gcc生成静态库和动态库.pdf”和“静态库.a与.so库文件的生成与使用.pdf”,请在Linux系统(Ubuntu)下如实仿做一遍。

1.sub1.c x2x

float x2x(float a,float b)
{
float c=a*b;
return c;
}

2.sub1.h

#ifndef SUB1_H
#define SUB1_H

float x2x(float a, float b);

#endif /* SUB1_H */

3.sub2.c x2y

float x2y(float a,float b)
{
float c=a/b;
return c;
}

4.sub2.h

#ifndef SUB2_H
#define SUB2_H

float x2y(float x1, float x2);

#endif /* SUB2_H */

5.main.c

#include <stdio.h>
#include “sub1.h”
#include “sub2.h”
int main()
{
float a=2,b=3,c=4,d=5;
float m,n;
m=x2x(a,b);
printf(“m=%f\n”,m);
n=x2x(c,d);
printf(“n=%f\n”,n);
printf(“result=%f\n”,x2y(m,n));
return 0;
}

编译.c->.o
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
生成目标文件 gcc -c A1.c A2.c
(2)生成静态库.a 文件。ar crv libafile.a A1.o A2.o
(3)使用.a 库文件,创建可执行程序。gcc -o test test.c libafile.a
(4)运行程序。 ./test

2.2生成共享库.so文件

2.3使用.so库文件,创建可执行程序

发现出现错误,运行ldd test 查看连接错误
在这里插入图片描述
3.实例使用库 (1)代码 sub1.c

float x2x(int m,int n) { float b; b = m * n; return b; } sub2.c

float x2y(int x, int y) { float z; z=x+y; return z; } sub.h

#ifndef SUB_H #define SUB_H float x2x(int m,int n); float x2y(int x,int y); #endif main.c

#include <stdio.h> #include “sub.h” int main() { int m=8,n=6; float x,y; x = x2x(m,n); y = x2y(m,n); printf(“%f\r\n”, x); printf(“%f\r\n”, y); return 0; } (2)将.c文件转成.o文件
在这里插入图片描述
(4)动态库 将两个目标文件用ar工具生成.so动态库,并用gcc链接。

如同前文,需要在root模式下进行
在这里插入图片描述
二、
Linux gcc常用命令
预处理:gcc -E test.c -o test.i
编译为汇编代码:gcc -S test.i -o test.s
汇编:gcc -c test.s -o test.o
连接:gcc test.o -o test
检错:gcc -pedantic test.c -o test
三、
一,概念
(一)stm32的堆、栈、全局变量的分配地址编程显示\n在一个STM32程序代码中,从内存高地址到内存低地址,依次分布着栈区、堆区、全局区(静态区)、常量区、代码区,其中全局区中高地址分布着.bss段,低地址分布着data段。
栈区(stack)
临时创建的局部变量存放在栈区。函数调用时,其入口参数存放在栈区。函数返回时,其返回值存放在栈区 const定义的局部变量存放在栈区。
2)堆区(heap)
堆区用于存放程序运行中被动态分布的内存段,可增可减。可以有malloc等函数实现动态分布内存。有malloc函数分布的内存,必须用free进行内存释放,否则会造成内存泄漏。
3)全局区(静态区)
全局区有.bss段和.data段组成,可读可写。
4)bss段
未初始化的全局变量存放在.bss段。
初始化为0的全局变量和初始化为0的静态变量存放在.bss段。
.bss段不占用可执行文件空间,其内容有操作系统初始化。
5) data段
已经初始化的全局变量存放在.data段。静态变量存放在.data段。.data段占用可执行文件空间,其内容有程序初始化。const定义的全局变量存放在.rodata段。
6)常量区
字符串存放在常量区。常量区的内容不可以被修改。
7)代码区
程序执行代码存放在代码区。字符串常量也有可能存放在代码区
(二)待验证的概念与结论 c程序的执行也就是静态的文件加载到内存下的过程,内存属性有两种,如下所示:
静态分配内存:是在程序编译和链接时就确定好的内存。
动态分配内存:是在程序加载、调入、执行的时候分配 回收的内存,栈的地址是向下增长,堆的地址是向上增长 静态变量是地址向下增长 全局常量是地址向上增长\n函数的地址向上增长 而由函数,一直到栈区,地址总体是从低地址到高地址,逐步递增的。
(一)打开ubuntu,编写一个.c文件,代码如下:
#include <stdio.h>
#include <stdlib.h>
int k1 = 1;
int k2;
static int k3 = 2;
static int k4;
int main( )
{ static int m1=2, m2;
int i = 1;
char *p;
char str[10] = “hello”;
char *var1 = “123456”;
char *var2 = “abcdef”;
int *p1=malloc(4);
int *p2=malloc(4);
free(p1);
free(p2);
printf(“栈区-变量地址\n”);
printf(" i:%p\n", &i);
printf(" p:%p\n", &p);
printf(" str:%p\n", str);
printf(“\n堆区-动态申请地址\n”);
printf(" %p\n", p1);
printf(" %p\n", p2);
printf(“\n.bss段\n”);
printf(“全局外部无初值 k2:%p\n”, &k2);
printf(“静态外部无初值 k4:%p\n”, &k4);
printf(“静态内部无初值 m2:%p\n”, &m2);
printf(“\n.data段\n”);
printf(“全局外部有初值 k1:%p\n”, &k1);
printf(“静态外部有初值 k3:%p\n”, &k3);
printf(“静态内部有初值 m1:%p\n”, &m1);
printf(“\n常量区\n”);
printf(“文字常量地址 :%p\n”,var1);
printf(“文字常量地址 :%p\n”,var2);
printf(“\n代码区\n”);
printf(“程序区地址 :%p\n”,&main);
return 0;

在这里插入图片描述
(一)在keil中对程序进行改写
将main.c修改如下
#include “stm32f10x.h”
#include “bsp_usart.h”

char global1[16];
char global2[16];
char global3[16];

int main(void)
{
char part1[16];
char part2[16];
char part3[16];

USART_Config();

printf(“part1: 0x%p\n”, part1);
printf(“part2: 0x%p\n”, part2);
printf(“part3: 0x%p\n”, part3);

printf(“global1: 0x%p\n”, global1);
printf(“global2: 0x%p\n”, global2);
printf(“global3: 0x%p\n”, global3);
while(1)
(二)编译并把HEX文件烧进芯片
(1)编译,烧录
在这里插入图片描述
在这里插入图片描述
编译之后,在串口软件上观察效果。

可以发现,STM32 在栈区和堆区的地址值是从上往下的在减小与Ubuntu下刚好相反。

四.总结 在C程序中,常量和变量存储在内存中的不同区域。常量通常存储在只读数据段中,而变量存储在堆栈或静态/全局数据段中。在实验中,我们通过使用取地址运算符&,可以获取变量或常量的地址。通过打印这些地址,我们可以观察到它们在内存中的分配情况。实验总结显示,常量的地址通常是固定的,而变量的地址会随着程序执行的不同而变化。这些实验结果对于理解C程序的内存管理和变量分配非常有帮助。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值