Uboot中C语言之指针数组

本文详细解析了指针数组与数组指针的概念及其区别,并通过具体代码实例展示了如何使用这两种数据结构。同时,文章还介绍了如何定义和使用指向函数的指针。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

回顾:https://blog.youkuaiyun.com/wangdapao12138/article/details/79406924

1.字面意思来理解指针数组与数组指针

1)指针数组的实质是一个数组,这个数组中存储的内容全部是指针变量。

2)数组指针的实质是一个指针,这个指针指向的是一个数组

2.分析指针数组与数组指针的表达式

1)int *p[5]; int (*p)[5];    int *(p[5]);

2)一般规律:int *p;(p是一个指针); int p[5];(p是一个数组)

总结:我们在定义一个符号时,关键在于:首先要搞清楚你定义的符号是谁(第一步:找核心);其次再来看谁跟核心最近、谁跟核心结合(第二步:找结合);以后继续向外扩展(第三步:继续向外结合直到整个符号完)。

3)如何核心和*结合,表示核心是指针;如果核心和[]结合,表示核心是数组;如果核心和()结合,表示核心是函数。

4)用一般规律来分析3个符号:

    第一个:int *p[5]; 核心是p,p是一个数组,数组有5个元素大,数组中的元素都是指针,指针指向的元素类型是int类型的;整个符号是一个指针数组。

    第二个,int (*p)[5];核心是p,p是一个指针,指针指向一个数组,数组有5个元素,数组中存的元素是int类型; 总结一下整个符号的意义就是数组指针。

    第三个,int *(p[5]); 解析方法和结论和第一个相同,()在这里是可有可无的。

下面是代码部分:

typedef int (init_fnc_t) (void);

/*这里定义了一个新的数据类型init_fnc_t,

*这个数据类型是参数为空,返回值为int的函数。PS:注意init_fnc_t并不是函数指针!!! 如果这样写就表示函数指针 typedef int (*init_fnc_t) (void);
*/

/*init_sequence是一个指针数组,数组元素指向的是init_fnc_t类型的函数*/

//init_sequence 是一个指针数组(数组元素为指针变量),指向的是init_fnc_t类型的函数组成的数组。数组的元素数据类型 init_fnc_t是参数为空,返回值为int的函数)
init_fnc_t *init_sequence[]=

我们来解析下这句话。对照int *p[5],我们知道init_sequence是一个指针,指向一个数组,数组元素是init_fnc_t类型的。

{
     cpu_init, /* basic cpu dependent setup */
基本的处理器相关配置 -- 
     board_init, /* basic board dependent setup */
基本的板级相关配置 -- 
     interrupt_init, /* set up exceptions */
初始化中断处理 -- 
     env_init, /* initialize environment */
初始化环境变量
     init_baudrate, /* initialze baudrate settings */
初始化波特率设置
     serial_init, /* serial communications setup */
初始化串口通讯设置
     console_init_f, /* stage 1 init of console */
控制台初始化阶段1
     display_banner, /* say that we are here */
打印u-boot信息
     dram_init, /* configure available RAM banks */
RAM banks 配置可用的RAM
     display_dram_config,
//显示RAM的配置大小
#if defined(CONFIG_VCMA9)|| defined(CONFIG_CMC_PU2)
     checkboard,
#endif
NULL,
};

/*init_fnc_ptr为指向函数指针的指针*/
    init_fnc_t **init_fnc_ptr;
/*init_fnc_ptr初始化指向init_sequence指针数组,下面的循环遇到NULL结束*/
    for (init_fnc_ptr= init_sequence;*init_fnc_ptr;++init_fnc_ptr)

    {
        if ((*init_fnc_ptr)()!= 0)

        {

           /*(*init_fnc_ptr)()为C中调用指针指向的函数*/
            hang ();
        }
    }

PS:指针数组和指向指针的指针 两者的主要区别:

就是,指针数组的数组名不能进行++操作(因为数组名仅仅代表一个地址!是一个常量!!),而指向指针的指针是 可以++的(因为它是一个变量!),所以这段源代码中,重新定义了一个指向函数指针的指针init_fnc_ptr来对指针数组 (init_sequence)进行操作. 操作也就是将各个准备初始化的函数的入口地址依次赋给init_fnc_ptr!而*init_fnc_ptr就正好对应arch_cpu_init这些 东西了,那么(*init_fnc_ptr)()就相当于arch_cpu_init() 了.

<think>好的,我现在需要帮助用户了解如何在U-Boot中使用C语言擦除MTD分区数据。首先,我得回忆一下U-Boot的基本知识。U-Boot是嵌入式系统中常用的引导加载程序,支持多种命令和操作,通常在启动阶段初始化硬件并加载操作系统。 用户的问题涉及到在U-Boot环境下用C语言擦除MTD分区。不过,我有点不确定,U-Boot本身主要是用C语言写的,但用户通常通过U-Boot的命令行接口(CLI)执行命令,而不是自己编写C代码。所以可能需要确认用户的具体需求:是希望在U-Boot中运行自定义的C代码来擦除分区,还是使用现有的U-Boot命令? 首先,我应该考虑U-Boot的标准方法。通常,擦除MTD分区可以使用`nand erase`或`mtd erase`命令,具体取决于硬件和U-Boot的配置。比如,使用NAND Flash的话,可能有`nand erase.part <partition-name>`或者指定偏移量和长度。用户可能已经知道这些命令,但希望用C语言实现类似功能,可能是为了集成到自定义启动流程中。 接下来,我需要思考在U-Boot中如何添加自定义的C代码。U-Boot允许用户添加命令,这需要编写一个C函数,并注册到U-Boot的命令列表中。例如,创建一个新的命令,调用MTD相关的API来执行擦除操作。 MTD子系统在U-Boot中负责管理存储设备,如NOR Flash、NAND Flash等。擦除操作需要获取MTD设备,找到对应的分区,然后调用擦除函数。可能需要用到`mtd_get_device()`、`mtd_erase()`等函数。需要注意的是,擦除操作的单位是擦除块(erase block),所以必须按块大小对齐。 然后,我需要考虑如何获取分区的信息。U-Boot通常通过环境变量或设备树(DTB)来定义MTD分区。可能需要解析这些信息来找到指定分区的偏移量和大小。例如,通过`mtdparts`环境变量来解析分区布局。 另外,权限和锁的问题也不可忽视。有些Flash设备可能有写保护机制,需要在擦除前确保该区域未加锁。否则,擦除操作会失败。此外,擦除过程中的错误处理也很重要,比如检查返回值,确保擦除成功完成。 可能还需要考虑代码的位置。用户的自定义命令应该放在U-Boot的源码树中,比如在`cmd/`目录下添加新的C文件,并修改Makefile和Kconfig来包含新命令。然后重新编译U-Boot,烧写到设备上测试。 不过,用户可能没有编译U-Boot的经验,所以是否需要简化步骤?或者用户是在询问如何在不进入操作系统的情况下,直接在U-Boot阶段执行擦除操作?这时候可能更倾向于使用现有命令,而不是编写C代码。 可能的误区是用户认为必须用C语言编写代码,但实际上U-Boot已经提供了命令行工具。比如,如果用户只是想擦除某个分区,可以直接在U-Boot命令行输入`mtd erase <partition-name>`。但若确实需要自定义逻辑,比如在特定条件下自动擦除,那么编写C代码是必要的。 总结下来,回答应该分两部分:首先介绍标准命令的使用方法,然后说明如何通过编写自定义C代码在U-Boot中实现擦除操作。同时需要提醒注意事项,如块对齐、错误处理、分区信息获取等。这样既覆盖了常见使用场景,也满足了需要定制化操作的用户需求。</think>在Linux的U-Boot中擦除MTD分区数据,可以通过以下步骤实现: --- ### 一、基本概念 1. **MTD分区** MTD(Memory Technology Device)是Linux内核中对Flash存储设备的抽象层,U-Boot通过MTD子系统管理Flash分区。 2. **U-Boot与C语言** U-Boot本身用C语言编写,用户可通过以下两种方式操作MTD: - **直接使用U-Boot内置命令**(推荐) - **编写自定义C代码**(需修改U-Boot源码) --- ### 二、使用U-Boot内置命令 在U-Boot命令行中直接执行擦除操作: ```bash # 查看MTD分区信息 U-Boot> mtd list # 擦除整个分区(例如擦除名为"kernel"的分区) U-Boot> mtd erase kernel # 擦除指定地址范围(起始地址0x100000,长度0x20000) U-Boot> mtd erase 0x100000 0x20000 ``` --- ### 三、通过C语言代码实现 若需自定义逻辑(如自动化擦除),需修改U-Boot源码: #### 1. 添加自定义命令 在U-Boot源码的 `cmd/` 目录下新建文件(如 `cmd_myerase.c`): ```c #include <common.h> #include <command.h> #include <mtd.h> static int do_myerase(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct mtd_info *mtd; u64 addr, len; int ret; // 参数校验 if (argc != 3) return CMD_RET_USAGE; // 获取MTD设备 mtd = get_mtd_device_nm("nand0"); if (IS_ERR(mtd)) { printf("MTD device not found\n"); return CMD_RET_FAILURE; } // 解析地址和长度 addr = simple_strtoul(argv[1], NULL, 16); len = simple_strtoul(argv[2], NULL, 16); // 执行擦除(需按擦除块对齐) ret = mtd_erase(mtd, addr, len); if (ret) { printf("Erase failed: %d\n", ret); return CMD_RET_FAILURE; } return CMD_RET_SUCCESS; } U_BOOT_CMD( myerase, 3, 0, do_myerase, "Erase MTD partition by address and length", "<start_addr> <length>" ); ``` #### 2. 编译并烧写U-Boot ```bash make menuconfig # 启用自定义命令 make ``` --- ### 四、注意事项 1. **擦除块对齐** Flash擦除操作必须按块大小(如4KB/128KB)对齐,否则会失败。 2. **分区信息匹配** 确保U-Boot的MTD分区定义(通过设备树或`mtdparts`环境变量)与内核一致。 3. **写保护** 某些Flash区域可能受硬件写保护,擦除前需解除保护。 4. **数据丢失风险** 误擦除关键分区(如U-Boot自身)会导致系统无法启动! --- ### 五、验证操作 擦除后可通过读操作验证: ```bash U-Boot> mtd read <addr> <length> <dest_addr> ``` 建议优先使用U-Boot内置命令,仅在需要深度定制时修改源码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值