C语言数组赋值一例

在移植内核时,发现一个驱动使用数组十分巧妙。
一般地,操作CPU某一外设寄存,不是直接使用完整的地址,而是通过相对地址来访问。比如,访问定时器,首先参考手册定义好定时器基地址,然后再定义寄存器(如控制寄存器、读数据寄存器等)对于定时器基地址的偏移地址。在使用时,一般都是使用偏移地址的,这样十分方便、快捷。如果有七、八个定时器,只需要定义好一个基地址数组、一个偏移地址数组,通过不同的序号就能访问不同的地址。
本文的例子是从驱动中抽象出来的。一个芯片平台系列中,对于特定外设,大部分的地址是相同的,但还是有个别不同,为了适应不同的芯片,代码也要做些处理。比如,这个系列中有十个寄存器,但另一个系统只有五个,其中大部分是共用的,为了共用代码,把所有的寄存器用枚举类型对一个数组进行访问,从而得到实际的偏移地址。
这里的数组赋值形式是我之前没见过,下面的例子中foo_regs数组,如果转化成实际值,变成:
static const u32 foo_regs[] = { [0] = 0x00, [3] = 0x48, [2] = 0x3c,};

这种赋值的好处在于,可以根据不同的情况使用不同的下标、不同的值。比如,同样是控制寄存器FOO_CTRL_REG,有的平台是0x3c,有的是0x3f,这样就可以通过不同的数组区别开来,而对外的访问接口,可以做到统一。

完整示例代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define u32 unsigned int

enum {
    FOO_ID_REG = 0,
    FOO_SYS_STAT_REG,
    FOO_CTRL_REG,
    FOO_COUNTER_REG,
};

static const u32 foo_regs[] = {
    [FOO_ID_REG]               = 0x00,
    [FOO_COUNTER_REG]          = 0x48,
    [FOO_CTRL_REG]             = 0x3c,
};

static const u32 bar_regs[] = {
    [FOO_ID_REG]               = 0x00,
    [FOO_CTRL_REG]             = 0x3f,
    [FOO_COUNTER_REG]          = 0x4f,
};

#define FOO_START               (1 << 0)
#define FOO_STOP               (1 << 1)

static u32 foo_read_reg(unsigned int timer, u32 reg)
{
     u32 tmp = 0;
  
    tmp = (timer + (foo_regs[reg] & 0xff));
  
    printf("%x: %x\n", reg, tmp);
}

static u32 foo_write_reg(unsigned int timer, u32 reg, u32 value)
{
     u32 tmp = 0;
  
    tmp = (timer + (bar_regs[reg] & 0xff));
  
    printf("%x: %x\n", reg, tmp);
}

int main(void)
{
    foo_read_reg(0x80084000, FOO_COUNTER_REG);
  
    foo_write_reg(0x80084000, FOO_COUNTER_REG, FOO_START);

    return 0;
}


运行结果:
3: 80084048
3: 8008404f

 

从这里学习到一个数组的赋值的方法,即实际赋值可以按不同的顺序(只要是合法的下标),而不是仅限于从0~N这样的顺序去赋值。


 李迟记于2014年2月28日

©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页