c pointer

本文解释了如何在嵌入式系统中使用C语言访问特定内存地址,通过定义宏来实现对内存地址的安全操作,并强调了使用volatile关键字的重要性。

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

今天与群里的 神 聊天时,我提出一个问题

#define LCD_CMD_ADDR (*((volatile unsigned char *)  0x6C080002))

怎么理解

他给出了很酷的答案,特此贴出来与大家分享

嵌入式系统编程,要求程序员能够利用C语言访问固定的内存地址。既然是个地址,那么按照C语言的语法规则,这个表示地址的量应该是指针类型。所以,知道要访问的内存地址后,比如0x5F,
   第一步是要把它强制转换为指针类型
(unsigned char *)0x5F,AVR的SREG是八位寄存器,所以0x5F强制转换为指向
unsigned char类型。
   volatile(可变的)这个关键字说明这变量可能会被意想不到地改变,这样编译器就不会去假设这个变量的值了。这种“意想不到地改变”,不是由程序去改变,而是由硬件去改变——意想不到。
   第二步,对指针变量解引用,就能操作指针所指向的地址的内容了
   *(volatile unsigned char *)0x5F
   第三步,小心地把#define宏中的参数用括号括起来,这是一个很好的习惯,所以#define SREG    (*(volatile unsigned char *)0x5F)

    类似的,如果使用一个32位处理器,要对一个32位的内存地址进行访问,可以这样定义#define RAM_ADDR     (*(volatile unsigned long *)0x0000555F)
    然后就可以用C语言对这个内存地址进行读写操作了
    读:tmp = RAM_ADDR;
    写:RAM_ADDR = 0x55;
zhiwei 发表于 2005-4-30 18:59 AVR 单片机

定义未volatile是因为它的值可能会改变,大家都知道为什么改变了;
如果在一个循环操作中需要不停地判断一个内存数据,例如要等待SREG的I标志位置位,因为SREG也是映射在SRAM空间,为了加快速度,编译器可能会编译出这样的代码:把SREG读取到Register中,然后不停地判断Register相应位。而不会再读取SREG,这样当然是不行了,因为程序或其它事件(中断等)会改变SREG,结果很可能是一个死循环出不来了。如果定义成volatile型变量,编译的代码是这样的:每次要操作一个变量的时候都从内存中读取一次。
#define SREG (*(volatile unsigned char *)0x5F) 之后,可以进行如下基本操作,
unsigned char temp,*ptr;
temp=SREG;把SREG值保存到temp中
SREG=temp;把temp的值赋给SREG
ptr = & SREG; 不知对否,大家试一下。

 

http://blog.ednchina.com/wind/1966686/Message.aspx

指针运算(Pointer Arithmetic)是C语言中非常重要的特性之一,允许程序员对指针进行算术操作。主要包括加法、减法以及比较等基本操作,这些操作使得能够方便地访问数组元素或是动态分配的内存块内的各个位置。 ### 指针的基本概念回顾 在讨论指针运算之前,先简短复习一下关于指针的基础知识: - **声明**: 定义一个指向特定类型数据项的指针变量。 ```c int *p; // 声明了一个指向整型(int) 的指针p char *q; // 声明了一个指向字符(char) 的指针q ``` - **初始化和赋值**: 把某个现有对象地址存储到指针当中去 ```c int a = 5; p = &a; // 将a 变量的位置存入了指针p 中 ``` - **解引用**: 获取当前由该指针对应的实际内容(即“间接寻址”) ```c printf("%d\n", *p); // 输出通过*p 得来的实际数值, 即变量a 内容 ``` --- ### 指针算术的应用场景及规则 #### 加法与自增(+ 和++) 当你向指针添加正值时,它会根据其所指向的数据类型大小自动递增相应的字节数,并移动至下一个合适偏移处继续表示有效的新地址。 假设我们有一个整数类型的数组arr[], 并创建相应的一个int 类型的指针ptr 来跟踪其中每个成员的变化过程: ```c int arr[] = {10, 20, 30}; int *ptr; // 初始化 ptr 到第一个元素地址上 ptr = arr; // 或者也可以写作: ptr=&arr[0]; printf("Value at location %p is %d.\n", (void *)ptr , *ptr ); ptr++; // 相对于原来增加了 sizeof(int)=4 Bytes (一般而言) printf("After incrementing pointer Value at location %p is %d .\n",(void *)ptr,*ptr); ``` 以上例子展示了如何利用简单的加法规则遍历整个一维线性表结构里的所有项目! ##### 减法规律(-) 相似地,如果从现有的某指定点开始减少距离,则同样依据基础单元尺寸决定最终返回的新目标坐标是否合法合理范围内即可完成预期功能任务. 再次回到刚才提到过的那个同样的整型数组样本... ```c ptr -=2 ; // 返回两格前的那个地方也就是第二个元素那里... printf("Decremented twice now points to second element whose value=%d \n ",*ptr ); ``` 注意这里要注意越界可能性问题哦~ 因为我们已经回到了比初始起点还要往前的状态啦! 最后就是两者之间差了多少个单位长度的问题解答咯~ ```c ptrdiff_t diff= ptr -&arr[0]; printf ("There are %td elements between them.",diff ); ``` 此表达式计算出了从原始首端直至目前所在为止经过了多少次跳跃跨越而成的结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值