符号即内存,即地址


不多说,上栗子~


不必局限于规定的类型,该放什么放什么



#include<stdio.h>

//符号即内存
int main()
{
	int nNum = 'BP51';
	int  *add ;
	char c1,c2,c3,c4;

//***********************************************
	c1 = '\101';		//八进制
	c2 =  '\x41';		//十六进制
	c3 = 'A';
	c4 = 65;
	printf("%c  ----  %c  ----  %c  ----  %c\n",c1,c2,c3,c4);
	printf("%d  ---  %d  ---  %d  ---  %d\n",c1,c2,c3,c4);


//***********************************************
	printf("%s\n",&nNum);
				
	//printf("====     %s\n",nNum);	这样是不对的,nNum是一个整形并非地址
	printf("%c\n",nNum);	//而整形可以转换为字符
	printf("%c\n",nNum >> (8*1));

	printf("%c\n",((char *)&nNum)[1]);	//转换为字符指针

	add = &nNum;	
	printf("%x\n",&add[3]);	//相当于加了 3*4个字节,因为单位为 int
	printf("%c\n\n",add[3]);

	printf("%x\n",add +3);
	printf ("%c\n\n",*(add+3)); //相当于加了 3*4个字节,因为单位为 int

	return 0;
}





<think> 我们正在讨论中断函数符号地址的计算方法。在嵌入式系统中,中断向量表(Interrupt Vector Table, IVT)是一个关键的数据结构,它存储了各个中断服务程序(ISR)的入口地址。当发生中断时,处理器会根据中断号(或异常类型)在中断向量表中查找对应的中断服务程序地址,然后跳转执行。 中断函数符号地址的计算主要涉及两个方面: 1. 中断向量表的位置(基地址)和每个中断向量的偏移量。 2. 中断服务程序函数的地址(即符号地址)如何被放入中断向量表。 下面我们以ARM Cortex-M系列处理器为例进行说明。 ### 一、中断向量表结构 在Cortex-M中,中断向量表位于内存的起始位置(默认地址0x00000000),但可以通过向量表偏移寄存器(VTOR)重定位。向量表的结构如下: - 第一个字(地址0x00000000)是初始堆栈指针(MSP)的值。 - 第二个字(地址0x00000004)是复位向量(Reset_Handler)的地址。 - 接下来的字依次为NMI、HardFault等异常向量的地址,然后是外部中断(IRQ)向量的地址。 每个向量占用4字节(32位地址),因此第n个中断向量的地址为: $$ \text{向量地址} = \text{VTOR} + 4 \times n $$ 其中,n为中断号(从0开始,复位向量n=0,NMI n=1,依此类推)。 ### 二、中断函数符号地址的获取 编译器在编译中断服务程序函数时,会为每个函数分配一个地址符号地址)。在链接阶段,这个地址将被确定。我们需要将中断服务程序的地址放入向量表中对应的位置。 通常有两种方式实现: #### 1. 通过启动文件(汇编)定义向量表 在启动文件(如startup_stm32fxxx.s)中,使用汇编语言定义向量表: ```assembly .section .isr_vector,"a",%progbits .globl __isr_vector __isr_vector: .word _estack .word Reset_Handler .word NMI_Handler .word HardFault_Handler ... .word EXTI0_IRQHandler // 外部中断0 ``` 这里,每个`.word`后面是一个符号(即函数名),链接器会将这些符号替换为实际地址。 #### 2. 通过C语言数组定义向量表(可重定位) 在C语言中,可以将向量表定义为一个函数指针数组,并利用链接脚本将其放置在指定位置: ```c typedef void (*vector_entry)(void); __attribute__ ((section(".isr_vector"))) vector_entry isr_vector[] = { (vector_entry)(&_estack), // 初始堆栈指针 Reset_Handler, NMI_Handler, ... EXTI0_IRQHandler }; ``` 其中,每个元素都是中断服务程序的函数指针。链接脚本(.ld文件)需要将`.isr_vector`段放置在正确的地址(通常是0x00000000)。 ### 三、中断函数符号地址的计算过程 当程序编译链接后,中断服务程序函数的地址(即符号地址)被确定。这些地址被填充到向量表的相应位置。处理器在发生中断时的行为如下: 1. 根据中断号(异常号)计算出向量表中的偏移量:`偏移量 = 中断号 × 4`。 2. 从向量表基地址(VTOR)+偏移量处读取一个32位的值,这个值就是中断服务程序的入口地址。 3. 跳转到该地址执行。 注意:Cortex-M的中断向量表基地址不一定在0x00000000,可以通过VTOR寄存器设置。例如,如果VTOR寄存器的值为0x20000000,那么第n个中断向量的地址为: $$ \text{向量地址} = 0x20000000 + 4 \times n $$ ### 四、实际调试中获取中断函数地址 在调试时,可以通过以下方式查看中断函数地址: - 在启动文件中,向量表里每个向量对应符号地址可以在链接后由map文件查看。 - 在调试器中,直接查看向量表所在内存位置的内容(每个中断向量占4字节,小端模式)。 例如,在Keil MDK中查看向量表内存: ``` Memory window: 0x00000000: 0x20001000 (_estack的值) 0x00000004: 0x08000101 (Reset_Handler的地址) 0x00000008: 0x08000123 (NMI_Handler的地址) ... ``` ### 五、相关问题 §§相关问题§§ 1. Cortex-M中如何动态更改中断服务程序函数? 2. 中断向量表如何重定位到RAM中以提高性能? 3. 在支持浮点单元的Cortex-M4中,中断处理函数需要额外保存寄存器吗? 以上内容参考了ARM Cortex-M编程手册[^1]以及STM32标准外设库的实现[^2]。 </think> ### 中断函数符号地址计算方法详解 在嵌入式系统中,中断函数符号地址的计算涉及处理器架构和中断控制器机制。以下是关键步骤: --- #### 一、基本原理 中断函数地址的计算公式: $$ \text{中断入口地址} = \text{向量表基址} + \text{中断号} \times \text{向量宽度} $$ 1. **向量表基址(VTOR)** - Cortex-M:默认`0x00000000`,可通过`SCB->VTOR`寄存器重定位 - x86:IDT(Interrupt Descriptor Table)基址由`IDTR`寄存器存储 2. **中断号(IRQn)** - 硬件定义:如STM32中EXTI0中断号为6,USART1为37 - 软件定义:自定义中断需在向量表预留位置 3. **向量宽度** - ARMv7-M:固定4字节(32位地址) - x86_32:8字节(门描述符) --- #### 二、计算流程(以ARM Cortex-M为例) ```c // 向量表定义(启动文件startup_stm32.s) __isr_vector: .word _estack // 0x00: 初始栈顶 .word Reset_Handler // 0x04: 复位向量 .word NMI_Handler // 0x08: NMI ... .word USART1_IRQHandler // 中断号37的偏移地址 // 计算USART1中断地址: uint32_t usart1_addr = (uint32_t)&__isr_vector + 4 * 37; ``` **关键步骤**: 1. 编译器将`USART1_IRQHandler`符号链接到具体地址 2. 链接脚本将`__isr_vector`放置到VTOR指定地址 3. 发生中断时,CPU自动执行: ```assembly ldr PC, [VTOR, #(37*4)] ; 加载PC寄存器 ``` --- #### 三、动态重定向技术 通过修改向量表实现运行时替换中断函数: ```c // 1. 获取原向量表地址 uint32_t *vtable = (uint32_t*)SCB->VTOR; // 2. 替换第6号中断(EXTI0) vtable[6] = (uint32_t)&my_new_handler; // 3. 验证(调试器查看内存) // 0x08000000 + 6*4 = 0x08000018 ``` > **注意**:修改前需关闭中断(`__disable_irq()`),避免竞争条件[^1] --- #### 四、特殊场景处理 1. **嵌套中断向量(NVIC)** Cortex-M的ISR地址需满足: $$ \text{地址} \mod 4 = 0 $$ 编译器自动添加对齐指令: ```assembly .thumb_func ; 确保LSB=1(Thumb模式) USART1_IRQHandler: ; 实际地址末位为1 ``` 2. **地址重映射** 若代码在RAM运行,需物理地址转虚拟地址: ```c uint32_t virt_addr = (uint32_t)&IRQ_Handler | 0x1; MMU_TLB_Map(0xFF000000, virt_addr); // 建立映射 ``` --- #### 五、调试验证方法 1. **反汇编查看** ```shell arm-none-eabi-objdump -D firmware.elf | grep "USART1_IRQHandler" # 输出:0800a3cd <USART1_IRQHandler>: ``` 2. **内存窗口查看** ```math \text{VTOR} + 37 \times 4 = 0x08000000 + 148 = 0x08000094 ``` 在0x08000094处应存储值0x0800a3cd(小端序:cd a3 00 08) ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值