链接指示符extern C

 程序员用链接指示符linkage directive 告诉编译器该函数是用其他的程序设计语言
编写的链接指示符有两种形式既可以是单一语句single statement 形式也可以是复
合语句compound statement 形式
// 单一语句形式的链接指示符
extern "C" void exit(int);
// 复合语句形式的链接指示符
extern "C" {
int printf( const char* ... );
int scanf( const char* ... );
}
// 复合语句形式的链接指示符
extern "C" {
#include <cmath>
}

===========

被extern "C"修饰的变量和函数是按照C语言方式编译和连接的;

未加extern “C”声明时的编译方式

首先看看C++中对类似C的函数是怎样编译的。

作为一种面向对象的语言,C++支持函数重载,而过程式语言C则不支持。函数被C++编译后在符号库中的名字与C语言的不同。例如,假设某个函数的原型为:

void foo( int x, int y );

该函数被C编译器编译后在符号库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字(不同的编译器可能生成的名字不同,但是都采用了相同的机制,生成的新名字称为“mangled name”)。

foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数void foo( int x, int y )与void foo( int x, float y )编译生成的符号是不相同的,后者为_foo_int_float。

同样地,C++中的变量除支持局部变量外,还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名,我们以"."来区分。而本质上,编译器在进行编译时,与函数的处理相似,也为类中的变量取了一个独一无二的名字,这个名字与用户程序中同名的全局变量名字不同。

未加extern "C"声明时的连接方式

假设在C++中,模块A的头文件如下:

// 模块A头文件 moduleA.h

#ifndef MODULE_A_H

#define MODULE_A_H

int foo( int x, int y );

#endif

在模块B中引用该函数:

// 模块B实现文件 moduleB.cpp

#include "moduleA.h"

foo(2,3);

实际上,在连接阶段,连接器会从模块A生成的目标文件moduleA.obj中寻找_foo_int_int这样的符号!

加extern "C"声明后的编译和连接方式

加extern "C"声明后,模块A的头文件变为:

// 模块A头文件 moduleA.h

#ifndef MODULE_A_H

#define MODULE_A_H

extern "C" int foo( int x, int y );

#endif

在模块B的实现文件中仍然调用foo( 2,3 ),其结果是:

(1)模块A编译生成foo的目标代码时,没有对其名字进行特殊处理,采用了C语言的方式;

(2)连接器在为模块B的目标代码寻找foo(2,3)调用时,寻找的是未经修改的符号名_foo。

在使用命令提示符解决 `BAD_SYSTIM_CONFIG_INFO` 错误时,通常涉及对系统定时器(如 SysTick)和系统时钟配置的检查与修复。此错误常见于嵌入式系统或实时操作系统(RTOS)中,表示系统定时器或时钟配置信息异常,可能由配置参数超出限制、时钟源未正确初始化或系统初始化顺序错误引起。 ### 检查并修复系统定时器配置 在嵌入式系统中,`SysTick_Config` 函数用于初始化系统定时器。若传入的 `ticks` 参数超过 `SysTick_LOAD_RELOAD_Msk`(通常为 `0x00FFFFFF`)所允许的最大值,则会导致配置失败,并返回错误标识 `1`。在命令提示符中可通过调用调试接口或使用调试器查看系统寄存器状态,确认配置是否正确。 ```c #include "core_cm3.h" void SysTick_Init(void) { if (SysTick_Config(SystemCoreClock / 1000)) { // 1ms interrupt // SysTick configuration failed while (1); } } ``` 确保系统时钟(如 `SystemCoreClock`)已正确初始化,并与芯片手册中定义的时钟树一致。例如在 STM32 系列微控制器中,需检查 RCC(Reset and Clock Control)配置是否正确,包括外部时钟源、PLL 倍频系数等参数。 ### 使用命令提示符检查系统配置 在某些开发环境中(如使用 J-Link 调试器或 OpenOCD),可通过命令提示符连接目标设备并读取寄存器内容,以验证 SysTick 配置状态。例如: ```bash > read32 0xE000E010 ``` 该命令读取 SysTick 控制和状态寄存器(CTRL),用于判断定时器是否已启动。类似地,可读取 LOAD 和 VAL 寄存器确认重载值和当前计数值: ```bash > read32 0xE000E014 # LOAD register > read32 0xE000E018 # VAL register ``` ### 解决多模块符号冲突问题 若系统中存在多个模块重复定义了相同符号(如全局变量 `WRBUFF`),可能导致链接错误,并间接影响系统配置信息加载。在命令提示符中使用 `nm` 或 `objdump` 工具可检查目标文件中的符号定义情况: ```bash $ arm-none-eabi-nm bsp_i2c_ee.o main.o | grep WRBUFF ``` 若发现多个定义,应将其中一个源文件中的定义改为 `extern` 声明,或改为静态变量(`static`),以避免符号冲突。 ### 示例:使用调试工具检查寄存器状态 在调试环境中,可使用如下命令检查 SysTick 寄存器状态: ```bash (gdb) x/x 0xE000E010 (gdb) x/x 0xE000E014 (gdb) x/x 0xE000E018 ``` 上述命令分别读取 CTRL、LOAD 和 VAL 寄存器,用于诊断 SysTick 是否正确配置。 ### 总结 通过命令提示符可以有效地诊断和修复 `BAD_SYSTIM_CONFIG_INFO` 错误。重点在于验证系统定时器配置是否符合硬件限制、确认系统时钟是否正确初始化,并检查是否存在符号重复定义问题。使用调试工具读取寄存器状态,有助于快速定位配置异常的位置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值