typedef和const之间的trap

本文探讨了C语言中const和typedef结合使用的复杂性及注意事项,通过实例详细解析了不同情况下const的位置对变量和指针的影响。

博客好久没有更新了,主要是因为工作忙,即便不忙也要看看书,工作了才发现好多东西根本就会直接忘记,因为我们工作用不到!比如c++的东西,现在连虚函数表都不快不记得了,惭愧咯!而且我还发现工作了,看书反倒成了一种非常好的休闲了,不过希望我的朋友,同学们都好.

现在就说说typedef和const之间的那么一道陷阱,而且还很深!

现在也是找工作的时间了,弄清楚这个还是很有好处的,或许很多公司就会用这个来欺负"弱小".

记得好像是<c专家编程>里面说提及了这个问题,上面说typedef和const一起使用之后const使用对象会和想象的不一样,具体的不记得了,n久以前看的书了,hoho,不记得了.

现在我就来说说我的理解,之间的代码就不注意命名规范了,还有一些工作的代码肯定也是不能贴了.

先给一个引子,如果我有一个全局变量,是一个二维数组,现在的问题就是,老板不喜欢全局变量,他要弄成一个static变量,需要封装一下,怎么弄,比如这个二维的变量是:

const int myapple[9][8]; //这里用apple做变量,呵呵,我现在不贩卖苹果哈哈!

那么我现在就要让这个静态函数能穿越文件,就用一个函数封装起来,然后,返回这个变量的地址,要么就用直接值拷贝的方法,把值按位复制除去都行,如下操作?

const int** Get_apple() { return myapple; }

明显不行,二者不是一个东西,int**是一个二维指针,而我的苹果myapple却是一个int (*)[8]类型的变量,这个问题我不知道一般的c语言的书籍里面涉及了否,不过如果好多c++的书籍里面还是涉及到了的.

那么现在的问题就很简单了,只要给一个适当的返回类型就ok了.这样?

const int (*)[8] Get_apple() { return myapple; }

有点简单,有点粗暴,却不那么有效!

引入typedef,我们可以把一个很复杂的类型用typedef来实现类型的替代,记住是typedef不是define.先定义类型,然后就是作为函数的返回值就ok咯.

typedef const int (*type)[8];

那么就肯简单了,如下给出我们一个正确实现:

typedef const int (*type)[8]; const int myapple[9][8] = {0}; type Get_apple() { return myapple; }

如此便ok了.

故事到这里就结束了?还没有!

继续看,我上面的type的定义里面加了一个const,下面我定义一个不加const的类型:

typedef int (*type_2)[8]; const type_2 myapple_2;

这两个类型的差别仅仅是一个const吗?当然不是,hoho,差别在与const是在星星(指针的星号)前后的问题了,type的类型决定了该类型定义的对象不可修改,因为它是在星号前面,或者说它修饰的是对象本身.而type_2呢,在做类型定义myapple_2的时候加上了const,是不是myapple不能改变了?不是,而是,指针不可变!二维的或许有点复杂,我们用一维指针来作为示例:

typedef char *xp; int main(int argc, _TCHAR* argv[]) { char a =100; const xp xp1 = &a; char *xp2 = &a; *xp1 = 1000; //1 xp1 = xp2; //2 return 0; }

xp可以说是一个自定义类型,我在定义xp1的时候加上了const修饰,那么从上面的程序来看,1处是没有问题的,在typedef之后,再在变量定义时候加的const实际上是被编译器放在了星号自后了,那么这个const就表示他修饰的是这个指针而不是变量本身,结果2处就错了,因为我视图修改指针xp1.

那我要把const应用与变量而不是指针,就要把const在typedef的时候带上,放星号前面,那么const就修饰的是变量了,如下:


typedef const char *xp; int _tmain(int argc, _TCHAR* argv[]) { char a =100; xp xp1 = &a; char *xp2 = &a; xp1 = xp2; //1 *xp1 = 1000; //2 return 0; }

这样的话,2处就会报错,原因上面已经说过了.

回到二维的,也就比较好理解了


typedef int (*type_2)[8]; const type_2 myapple_2;

const修饰的是后面数组的地址了.自然也就相当于:


int (*const type_2)[8];

如下,同样也可以给出一个例子:


typedef int (*type_2)[8]; int _tmain(int argc, _TCHAR* argv[]) { int (*const a)[8] = {0}; const type_2 ty1 = a; return 0; }

同样:


typedef const int (*type)[8]; int _tmain(int argc, _TCHAR* argv[]) { const int b[8] = {0}; const int xx[2][8]= {0}; type ty1 = xx; ty1[1][1] = 10; //1 return 0; }

这个const就是修饰的变量的值了,1处自然也不对了.

最后还有一个问题要说明的是typedef char *xp;得到的xp类型,可以给他赋值变量的地址,或者数组首元素的地址:


typedef char *xp; int _tmain(int argc, _TCHAR* argv[]) { char a[100] = "13edd"; char b = 'a'; xp myxp = &b; myxp = a; return 0; }

上面的程序里面,只要是能表示一维的都可以给myxp赋值,但是类型一定要完全一致.这里容易出两个问题:
1.一维指针但是类型不一致,当然了,c语言给我们提供了强制类型转换;
2.取数组名的地址,再给myxp赋值,这样也是不对的,因为维度不匹配:


typedef char *xp; int _tmain(int argc, _TCHAR* argv[]) { char a[100] = "13edd"; char b = 'a'; xp myxp = &b; myxp = a; myxp = &a; //1 return 0; }

1处就明显不对了,但是有人说,数组名和数组名取引用是一个值啊!却是,但是,对于编译器而言,两者是不一样的,a是char*,而&a是char (*)[100]的类型,a+1得到的是a[1]的地址,而&a+1得到的是什么?我想稍微注意点的同志们都知道是下一个100大小的数组的首地址了,也就是a[100]这个本不应该存在的地址了,而且仅仅是值一样,还是一个char (*)[100]的类型.这个就不说远了.有需要的可以再写一篇文章了.

对于typedef一个二维的指针也可以用类型的方法初始化:

typedef char (*type)[8]; int _tmain(int argc, _TCHAR* argv[]) { char a[8] = "13edd"; char b[2][8] = {"ddd", "ccc"}; type myxp = &a; myxp = b; myxp = &b; //1 myxp = b[1]; //2 return 0; }

这里1和2自然也是不对的,因为他们的维度也不匹配!

就说这么多吧,好累,下班手工回家咯!
希望大家有什么意见,可以提出来,一起学习.

非常好,我们现在结合你提供的 `lbdInit()` 初始化函数风格,以及典型的嵌入式网络设备架构(CLI → UC → Protocol → Adapter → SDK),来**完整实现一个 Smart Link 与 Monitor Link 模块的核心初始化主任务逻辑**。 我们将: - 遵循相同的编码规范(PAL 抽象层、消息队列、互斥锁、TPCL 注册等) - 实现 `smartLinkInit()` `smartLinkTask()` - 支持 Monitor Link 组联动 - 使用私有 EtherType 报文进行 Flush 消息传递 - 支持端口角色切换(主/备)链路状态监控 --- ### ✅ 功能目标 | 特性 | 支持情况 | |------|----------| | 主备链路快速倒换(<50ms) | ✅ | | 发送 Flush 报文清除对端 MAC 表 | ✅ | | Monitor Link:上行故障触发下行阻塞 | ✅ | | 多 Smart Link 组 | ✅ | | TPCL trap 上送 CPU | ✅ | | 线程 + 定时器驱动 | ✅ | --- ## 🧩 一、头文件定义(smart_link.h) ```c #ifndef _SMART_LINK_H_ #define _SMART_LINK_H_ #include "pal_types.h" #include "pal_mutex.h" #include "pal_thread.h" #include "pal_msgq.h" #include "tpcl.h" #define SMART_LINK_MAX_GROUPS 8 #define SMART_LINK_MAX_PORTS_PER_GROUP 2 // master + slave #define SMART_LINK_FLUSH_ETHERTYPE 0x8902 #define SMART_LINK_DEFAULT_VLAN 1 #define SMART_LINK_STATE_MASTER 1 #define SMART_LINK_STATE_SLAVE 2 #define SMART_LINK_STATE_BLOCKED 3 #define MONITOR_LINK_MAX_GROUPS 8 #define MONITOR_LINK_MAX_UPLINKS 4 #define MONITOR_LINK_MAX_DOWNLINKS 8 typedef struct { UINT32 enable; UINT32 interval; // flush msg send interval (ms) UINT32 recovery_time; // wait time before switchover (ms) } SMART_LINK_GLOBAL_CFG; typedef struct { int port_id; int state; // master/slave/blocked int link_status; // up/down int pending_switch; // 标记是否需要倒换 } SL_PORT; typedef struct { int group_id; int enable; int active_port; // 当前活动端口 SL_PORT ports[SMART_LINK_MAX_PORTS_PER_GROUP]; UINT8 da[6]; // 目的MAC: 01-00-0C-CD-CD-D0 UINT8 sa[6]; // 源MAC(取自CPU MAC) int flush_timer_tick; TPCL_ENTRY_ID trap_id; } SMART_LINK_GROUP; typedef struct { int group_id; int enable; int uplink_ports[MONITOR_LINK_MAX_UPLINKS]; int uplink_count; int downlink_ports[MONITOR_LINK_MAX_DOWNLINKS]; int downlink_count; } MONITOR_LINK_GROUP; // 全局变量 extern SMART_LINK_GROUP *g_sl_groups[SMART_LINK_MAX_GROUPS]; extern MONITOR_LINK_GROUP *g_ml_groups[MONITOR_LINK_MAX_GROUPS]; extern PAL_MUTEX_T g_sl_mutex; extern PAL_MSGQ_ID g_sl_msgq; extern PAL_THREAD_T g_sl_task_id; extern int g_sl_init_done; // 消息类型 typedef enum { SL_MSG_TYPE_NONE = 0, SL_MSG_TYPE_PORT_LINK_UP, SL_MSG_TYPE_PORT_LINK_DOWN, SL_MSG_TYPE_SEND_FLUSH, SL_MSG_TYPE_SWITCHOVER, SL_MSG_TYPE_MONITOR_LINK_EVENT } SL_MSG_TYPE; typedef struct { SL_MSG_TYPE type; int port_id; int group_id; int timestamp; } SL_MSG; // 函数声明 int smartLinkInit(void); void smartLinkTask(void *arg); int monitorLinkPortAdd(int ml_group, int uplink, int downlink); int slSendFlushPacket(int group_id); #endif /* _SMART_LINK_H_ */ ``` --- ## 🧱 二、核心实现(smart_link.c) ```c #include "smart_link.h" #include "ucSmartLink.h" // 用户配置获取接口 #include "sw_api.h" // 假设存在 switch 控制 API #include "pal_time.h" #include "getMacAddress.h" // 全局变量定义 SMART_LINK_GROUP *g_sl_groups[SMART_LINK_MAX_GROUPS] = {0}; MONITOR_LINK_GROUP *g_ml_groups[MONITOR_LINK_MAX_GROUPS] = {0}; PAL_MUTEX_T g_sl_mutex = NULL; PAL_MSGQ_ID g_sl_msgq = NULL; PAL_THREAD_T g_sl_task_id = NULL; int g_sl_init_done = 0; static const char *SL_DA_MAC = "\x01\x00\x0C\xCD\xCD\xD0"; // 标准DA /** * @brief 初始化 Smart Link 模块 */ int smartLinkInit(void) { int i, j; SMART_LINK_GLOBAL_CFG *cfg = NULL; if (g_sl_init_done) { return 0; } // 创建互斥量 g_sl_mutex = pal_mutex_create("slMutex"); if (!g_sl_mutex) { return -1; } // 创建消息队列 g_sl_msgq = pal_msgQ_create("/slMsgQ", 100, sizeof(SL_MSG), PAL_MQ_READ_WRITE); if (g_sl_msgq == PAL_MQ_ERROR) { pal_mutex_delete(g_sl_mutex); return -1; } // 分配 Smart Link 组 for (i = 0; i < SMART_LINK_MAX_GROUPS; i++) { SMART_LINK_GROUP *sl = (SMART_LINK_GROUP *)pal_malloc(sizeof(SMART_LINK_GROUP)); if (!sl) continue; memset(sl, 0, sizeof(SMART_LINK_GROUP)); sl->group_id = i; sl->enable = 0; sl->active_port = -1; memcpy(sl->da, SL_DA_MAC, 6); getMacAddress(sl->sa); // 获取本机MAC作为SA for (j = 0; j < SMART_LINK_MAX_PORTS_PER_GROUP; j++) { sl->ports[j].port_id = -1; sl->ports[j].state = SMART_LINK_STATE_BLOCKED; sl->ports[j].link_status = 0; sl->ports[j].pending_switch = 0; } g_sl_groups[i] = sl; } // 分配 Monitor Link 组 for (i = 0; i < MONITOR_LINK_MAX_GROUPS; i++) { MONITOR_LINK_GROUP *ml = (MONITOR_LINK_GROUP *)pal_malloc(sizeof(MONITOR_LINK_GROUP)); if (!ml) continue; memset(ml, 0, sizeof(MONITOR_LINK_GROUP)); ml->group_id = i; ml->enable = 0; ml->uplink_count = 0; ml->downlink_count = 0; g_ml_groups[i] = ml; } // 加载用户配置 cfg = ucSmartLinkGetCfg(); if (cfg) { // 应用全局配置(可扩展) } else { // 默认值 } // 注册 TPCL 处理(接收 Flush 报文) if (slInitTpcl() != 0) { goto err_out; } // 注册底层事件回调 notify_reg(NOTIFY_LINK_UP, slLinkUpCallback, NOTIFY_REG_PRI_MEDIUM); notify_reg(NOTIFY_LINK_DOWN, slLinkDownCallback, NOTIFY_REG_PRI_MEDIUM); notify_reg(NOTIFY_VLAN_DEL, slVlanDelCallback, NOTIFY_REG_PRI_LOW); // 创建主任务线程 g_sl_task_id = pal_thread_create("slTask", 8192, 100, smartLinkTask, NULL); if (g_sl_task_id == PAL_THREAD_ERROR) { goto err_out; } g_sl_init_done = 1; return 0; err_out: // 错误清理(简化版) pal_msgQ_delete(g_sl_msgq); pal_mutex_delete(g_sl_mutex); return -1; } /** * @brief 主任务循环 */ void smartLinkTask(void *arg) { SL_MSG msg; int ret; while (1) { ret = pal_msgQ_receive(g_sl_msgq, (char*)&msg, sizeof(SL_MSG), 100); // 100ms timeout if (ret == sizeof(SL_MSG)) { pal_mutex_lock(g_sl_mutex); switch (msg.type) { case SL_MSG_TYPE_PORT_LINK_UP: slHandlePortLinkUp(msg.port_id); break; case SL_MSG_TYPE_PORT_LINK_DOWN: slHandlePortLinkDown(msg.port_id); break; case SL_MSG_TYPE_SWITCHOVER: slDoSwitchover(msg.group_id); break; case SL_MSG_TYPE_SEND_FLUSH: slSendFlushPacket(msg.group_id); break; case SL_MSG_TYPE_MONITOR_LINK_EVENT: mlHandleUplinkFailure(msg.group_id); break; default: break; } pal_mutex_unlock(g_sl_mutex); } // 定时处理(模拟每10ms tick) for (int i = 0; i < SMART_LINK_MAX_GROUPS; i++) { if (g_sl_groups[i] && g_sl_groups[i]->enable) { g_sl_groups[i]->flush_timer_tick++; if (g_sl_groups[i]->flush_timer_tick >= 100) { // 1s 发一次 flush(示例) SL_MSG snd = {.type = SL_MSG_TYPE_SEND_FLUSH, .group_id = i}; pal_msgQ_send(g_sl_msgq, (char*)&snd, sizeof(SL_MSG), 1); g_sl_groups[i]->flush_timer_tick = 0; } } } } } /** * @brief 发送 Flush 报文(用于倒换后通知对端刷新FDB) */ int slSendFlushPacket(int group_id) { SMART_LINK_GROUP *sl = g_sl_groups[group_id]; UINT8 pkt[64]; int len = 0; if (!sl || !sl->enable) return -1; // 构造以太网头部 memcpy(pkt, sl->da, 6); memcpy(pkt+6, sl->sa, 6); pkt[12] = (SMART_LINK_FLUSH_ETHERTYPE >> 8) & 0xFF; pkt[13] = SMART_LINK_FLUSH_ETHERTYPE & 0xFF; len = 14; // 可选:添加VLAN tag // insert_8021q_tag(pkt, &len, SMART_LINK_DEFAULT_VLAN); // 调用底层发送函数(通过 tppacket 或 raw socket) if (sw_send_raw_to_port(sl->active_port, pkt, len) != 0) { return -1; } return 0; } /** * @brief 处理端口UP事件 */ void slHandlePortLinkUp(int port_id) { for (int i = 0; i < SMART_LINK_MAX_GROUPS; i++) { SMART_LINK_GROUP *sl = g_sl_groups[i]; if (!sl || !sl->enable) continue; for (int j = 0; j < SMART_LINK_MAX_PORTS_PER_GROUP; j++) { if (sl->ports[j].port_id == port_id) { sl->ports[j].link_status = 1; if (sl->active_port == -1 || sl->ports[j].state == SMART_LINK_STATE_MASTER) { slActivatePort(i, j); // 激活主端口 } } } } } /** * @brief 执行倒换:从主切到备 */ void slDoSwitchover(int group_id) { SMART_LINK_GROUP *sl = g_sl_groups[group_id]; int new_active = -1; if (!sl || !sl->enable) return; // 查找可用的slave端口 for (int j = 0; j < SMART_LINK_MAX_PORTS_PER_GROUP; j++) { if (sl->ports[j].state == SMART_LINK_STATE_SLAVE && sl->ports[j].link_status == 1) { new_active = j; break; } } if (new_active != -1 && sl->active_port != new_active) { sl->active_port = new_active; // 关闭原端口(若存在) // sw_set_port_state(old_port, BLOCKING); // 开启新端口 // sw_set_port_state(sl->ports[new_active].port_id, FORWARDING); // 发送Flush报文 SL_MSG flush_msg = {.type = SL_MSG_TYPE_SEND_FLUSH, .group_id = group_id}; pal_msgQ_send(g_sl_msgq, (char*)&flush_msg, sizeof(SL_MSG), 1); // 通知Monitor Link SL_MSG ml_msg = {.type = SL_MSG_TYPE_MONITOR_LINK_EVENT, .group_id = group_id}; pal_msgQ_send(g_sl_msgq, (char*)&ml_msg, sizeof(SL_MSG), 1); } } /** * @brief Monitor Link:上行链路故障处理 */ void mlHandleUplinkFailure(int ml_group_id) { MONITOR_LINK_GROUP *ml = g_ml_groups[ml_group_id]; int uplink_up = 0; if (!ml || !ml->enable) return; for (int i = 0; i < ml->uplink_count; i++) { if (sw_get_port_link_status(ml->uplink_ports[i]) == LINK_UP) { uplink_up = 1; break; } } // 所有上行都DOWN,则阻塞所有下行端口 for (int i = 0; i < ml->downlink_count; i++) { int port = ml->downlink_ports[i]; if (uplink_up) { sw_set_port_state(port, PORT_STATE_FORWARDING); } else { sw_set_port_state(port, PORT_STATE_BLOCKING); } } } /** * @brief 添加 Monitor Link 映射 */ int monitorLinkPortAdd(int ml_group, int uplink, int downlink) { MONITOR_LINK_GROUP *ml = g_ml_groups[ml_group]; if (!ml || !ml->enable) return -1; if (ml->uplink_count < MONITOR_LINK_MAX_UPLINKS && find_in_array(ml->uplink_ports, ml->uplink_count, uplink) == -1) { ml->uplink_ports[ml->uplink_count++] = uplink; } if (ml->downlink_count < MONITOR_LINK_MAX_DOWNLINKS && find_in_array(ml->downlink_ports, ml->downlink_count, downlink) == -1) { ml->downlink_ports[ml->downlink_count++] = downlink; } return 0; } /* 辅助函数(简化) */ int find_in_array(int *arr, int len, int val) { for (int i = 0; i < len; i++) if (arr[i] == val) return i; return -1; } ``` --- ## 🔗 三、关键点说明 | 功能 | 实现方式 | |------|----------| | **Flush 报文发送** | 构造 EtherType=0x8902 的帧,从 active port 发出 | | **倒换机制** | 主链路断开 → 触发 `SL_MSG_TYPE_SWITCHOVER` → 切换 active port | | **Monitor Link** | 上行DOWN → 自动阻塞下行端口 | | **TPCL 注册** | 需实现 `slInitTpcl()` 将 0x8902 报文 trap 到 CPU | | **线程模型** | 单主任务 + 消息队列 + 定时轮询 | | **端口控制** | 调用 `sw_set_port_state()` 实际操作硬件 | --- ## 📌 四、后续需补充的模块 1. **`slInitTpcl()`** —— 注册 TPCL 规则(匹配 EtherType + VLAN) 2. **`slFlushPacketHandler()`** —— 收到 Flush 报文时调用,用于清除本地 FDB 3. **CLI 命令集成** —— 如 `smart-link group 1 master-port gigabitethernet 0/1` 4. **配置持久化(UC 层)** 5. **OAM 检测替代链路状态**(更精准判断链路健康) ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值