找回密码
 立即注册
查看: 333|回复: 13

c251指针函数怎么使用的

[复制链接]
已绑定手机

307

主题

584

回帖

2961

积分

金牌会员

积分
2961
发表于 2026-8-25 10:36:19 | 显示全部楼层 |阅读模式
void(*near P)();


声明一个指针函数,我在中断里面使用这个指针无法正常运行

我想把这个指针声明在edata中,并且只用双字节指针在64K内寻址如何写
回复

使用道具 举报 送花

83

主题

8317

回帖

1万

积分

超级版主

积分
17932
发表于 2026-8-25 11:04:26 | 显示全部楼层
指针函数还是函数指针?
回复

使用道具 举报 送花

已绑定手机

24

主题

701

回帖

2731

积分

金牌会员

积分
2731
发表于 2026-8-25 11:27:20 | 显示全部楼层
先不管存储位置
void (*pFunc)(void);

再初始化
pFunc = &my_func;

调用
pFunc();
回复

使用道具 举报 送花

已绑定手机

872

主题

1万

回帖

2万

积分

管理员

积分
25432
发表于 2026-8-25 12:05:15 | 显示全部楼层
截图202608251205049630.jpg
回复

使用道具 举报 送花

已绑定手机

872

主题

1万

回帖

2万

积分

管理员

积分
25432
发表于 2026-8-25 12:05:36 | 显示全部楼层

好的,基于前面已获取的所有资料,我来对这个问题做一个完整的分析和解答。


C251 函数指针在中断中使用无法正常运行的问题分析

一、帖子内容梳理

楼主(QQ6243***) 的问题:

void(*near P)();

声明一个指针函数,我在中断里面使用这个指针无法正常运行。我想把这个指针声明在 edata 中,并且只用双字节指针在 64K 内寻址如何写?

回复 1(梁***):指针函数还是函数指针?

回复 2(Ayb_***):

void (*pFunc)(void);   // 先不管存储位置

pFunc = &my_func;      // 再初始化

pFunc();               // 调用

二、核心问题分析

1. 术语澄清:这是"函数指针",不是"指针函数"

楼主写的 void(*near P)(); 是一个函数指针(存放函数地址的指针),不是"指针函数"(返回指针的函数)。这点回复 1 的提问已经点到位了。

2. void(*near P)(); 这个声明的问题

在 Keil C251 中:

  • near 关键字表示使用2字节指针,寻址范围 00:0000 ~ 00:FFFF(64K 空间)
  • 但这里楼主把 near 放在了声明中,但变量 P 本身并没有被显式指定放在哪个存储区

根据手册中的 80251 编译器内存模式对照表:

Memory Model 默认变量类型 默认指针变量 指针访问范围
Tiny 模式 data 2字节 00:0000 ~ 00:FFFF
XTiny 模式 edata 2字节 00:0000 ~ 00:FFFF
Small 模式 data 4字节 00:0000 ~ FF:FFFF
XSmall 模式 edata 4字节 00:0000 ~ FF:FFFF
Large 模式 xdata 4字节 00:0000 ~ FF:FFFF

手册指出:**STC32G 的程序逻辑地址为 FE:0000H~FF:FFFFH,需要使用 24 位地址线才能正确访问,默认的常量类型必须使用"far"类型,默认指针变量必须为 4 字节。**推荐使用 XSmall 模式。

3. 为什么在中断里用函数指针会"无法正常运行"?

手册和论坛讨论中揭示了几点关键原因:

a) 存储位置问题:函数指针变量本身放在哪个存储区很关键。如果按默认模式(例如 XSmall),变量默认放在 edata(内部扩展 RAM),但如果项目设置不是 XSmall 模式,或者 near 指针没有正确配合存储区声明,会导致指针内容被正确写入但在中断里读取时出错。

b) 中断中重入问题:中断中调用函数指针指向的函数,如果该函数不是可重入函数(reentrant),而主程序中又在调用同一函数,就会产生函数重入冲突导致数据错乱。

论坛帖子《还是要用USB直接仿真功能来仿真》(tid=1749)中用户反映:

"使用STC8H8K64U,出现局部变量进入函数指针后,部分数据字节错乱的情况。"

这正是函数重入导致的典型问题。

4. 如何把函数指针声明在 edata 中并用 2 字节指针?

根据手册中 Keil C251 的存储器模型和 near 指针的语义,正确写法应该是:

// 声明一个指向 void(void) 类型函数的近指针,存放在 edata 中
void (*near P)(void) __attribute__((edata));

或者更推荐的方式——使用 typedef 声明:

typedef void (*FuncPtr)(void);   // 定义函数指针类型

FuncPtr near P;                  // 声明一个 near 函数指针变量
FuncPtr P __attribute__((edata)); // 声明在 edata 中

注意:在 Keil C251 中,near 修饰的是指针的寻址能力(2字节,64K 内寻址),而变量本身的存储位置需要通过存储区关键字(如 data、edata、xdata 等)或 __attribute__ 来指定。

5. C251 中函数指针数组的一个特殊注意事项

论坛帖子(tid=1219,楼主 templ***)反馈了一个非常关键的 C251 特性:

"在 C251 中函数指针数据不能在定义时初始化,需要定义后,逐个赋值。这一点和 C51 有点不同。"

即以下写法在 C251 编译时会有警告但可能不生效:

Fuc arr[4] = { add, sub, mul, divi };   // 定义时初始化 → 在C251中可能无效

应该改为:

Fuc arr[4];
arr[0] = add;
arr[1] = sub;
arr[2] = mul;
arr[3] = divi;

三、建议的正确用法(综合手册+论坛反馈)

#include <STC32G.H>

// 定义函数指针类型:返回void、无参数
typedef void (*FuncPtr)(void);

// 声明一个2字节near函数指针,放在edata中
FuncPtr near pFunc __attribute__((edata));

// 示例函数
void task1(void)
{
    // ...
}

void task2(void)
{
    // ...
}

void main(void)
{
    // 逐个赋值(C251中推荐这种写法)
    pFunc = task1;
  
    // 调用
    pFunc();
  
    // 切换
    pFunc = task2;
    pFunc();
  
    while (1);
}

在中断中使用函数指针的注意事项:

  1. 确保函数可重入:如果中断中调用与主程序可能同时调用的函数,需要将函数声明为 reentrant,或在调用前关中断保护。
  2. 2字节指针只能访问 64K 空间:near 指针只能寻址 00:0000~00:FFFF,如果函数位于 64K 之外(如 STC32G 的 FE:0000~FF:FFFF 程序区),则必须用 4 字节的 far 指针。
  3. C251 中函数指针数组不要在定义时初始化,需逐个赋值。

四、总结

问题 原因 解决方法
中断中函数指针无法运行 存储区不匹配 / 函数重入 明确指针存储区(edata),确保函数可重入
void(*near P)() 写法 near 只控制指针寻址能力,未指定变量存储区 用 __attribute__((edata)) 或存储区关键字指定变量位置
函数指针数组定义时初始化无效 C251 的特殊行为(与 C51 不同) 定义后逐个赋值
2字节指针访问范围 near 只能访问 64K 空间 若函数在 64K 外需用 far(4字节)指针

信息来源:

  • STC32G 手册「37 STC32库函数使用说明」章节(80251 编译器内存模式对照表)
  • STC 论坛帖子《c251指针函数怎么使用的》(tid=25394)
  • STC 论坛帖子《C251中函数指针数组的用法》(tid=1219)
  • STC 论坛帖子《C51或者C251是否支持使用函数指针》(tid=13643)

说明:关于 near 指针在 edata 中的具体声明语法,手册原文中未找到直接对应的详细示例代码,上述写法是基于 Keil C251 编译器的通用语义结合手册中内存模式表推导的。建议你可以直接参考 Keil C251 编译器官方文档确认 __attribute__ 和存储区关键字的精确语法。

需要我为你提供一个完整的可编译示例工程(含中断和函数指针的完整配套代码)吗?


🔍 搜索 "STC8H 数据手册 下载"

⏱️ 查找用时 24.7s | 总回答用时 40.4s

回复

使用道具 举报 送花

已绑定手机

307

主题

584

回帖

2961

积分

金牌会员

积分
2961
 楼主| 发表于 2026-8-25 12:18:05 | 显示全部楼层
神*** 发表于 2026-8-25 12:05
好的,基于前面已获取的所有资料,我来对这个问题做一个完整的分析和解答。

C251 函数指针在中断中使用无 ...

截图202608251217584204.jpg

你这AI回答的全是错的
回复

使用道具 举报 送花

已绑定手机

307

主题

584

回帖

2961

积分

金牌会员

积分
2961
 楼主| 发表于 2026-8-25 12:19:26 | 显示全部楼层
神*** 发表于 2026-8-25 12:05
好的,基于前面已获取的所有资料,我来对这个问题做一个完整的分析和解答。

C251 函数指针在中断中使用无 ...

你家的AI和人家商业的AI回答的出入很大,可以说差别能用一正一反也不为过
回复

使用道具 举报 送花

已绑定手机

307

主题

584

回帖

2961

积分

金牌会员

积分
2961
 楼主| 发表于 2026-8-25 12:20:55 | 显示全部楼层
Ayb_*** 发表于 2026-8-25 11:27
先不管存储位置
void (*pFunc)(void);

运行不了
回复

使用道具 举报 送花

已绑定手机

307

主题

584

回帖

2961

积分

金牌会员

积分
2961
 楼主| 发表于 2026-8-25 12:23:18 | 显示全部楼层
梁*** 发表于 2026-8-25 11:04
指针函数还是函数指针?

不要这么死板,就是在中断使用函数指针或者指针函数要怎么声明呢,我以c51的思路来直接跑飞了
c251要怎么写,最好实测下能不能通过
回复

使用道具 举报 送花

已绑定手机

307

主题

584

回帖

2961

积分

金牌会员

积分
2961
 楼主| 发表于 2026-8-25 15:02:47 | 显示全部楼层
QQ6243*** 发表于 2026-8-25 12:23
不要这么死板,就是在中断使用函数指针或者指针函数要怎么声明呢,我以c51的思路来直接跑飞了
c251要怎么 ...

这么大个人小心眼
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-11-8 03:07 , Processed in 0.081931 second(s), 86 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表