ifndef
#ifndef SDT
int GpioPolledExample(u16 DeviceId, u32 *DataRead);
#else
int GpioPolledExample(UINTPTR BaseAddress, u32 *DataRead);
#endif
#ifndef SDT
检查是否没有定义宏 SDT。如果没有定义 SDT,则编译下面的代码:
int GpioPolledExample(u16 DeviceId, u32 *DataRead);
这里声明了一个函数 GpioPolledExample,它接受两个参数:
u16 DeviceId:一个16位的无符号整数,表示设备的ID。
u32 *DataRead:一个指向32位无符号整数的指针,用于存储读取的数据。
2.
#else
如果定义了宏 SDT,则编译下面的代码:
int GpioPolledExample(UINTPTR BaseAddress, u32 *DataRead);
这里声明了另一个版本的函数 GpioPolledExample,它接受两个参数:
UINTPTR BaseAddress:一个无符号整数类型的指针,表示设备的基地址。
u32 *DataRead:同样是一个指向32位无符号整数的指针,用于存储读取的数据。
3.
#endif
结束条件编译块。
指针
int p; //这是一个普通的整型变量
int *p; //首先从P 处开始,先与*结合,所以说明P 是一个指针,然后再与int 结合,说明指针所指向的内容的类型为int 型.所以P是一个返回整型数据的指针
int p[3]; //首先从P 处开始,先与[]结合,说明P 是一个数组,然后与int 结合,说明数组里的元素是整型的,所以P 是一个由整型数据组成的数组
int *p[3]; //首先从P 处开始,先与[]结合,因为其优先级比*高,所以P 是一个数组,然后再与*结合,说明数组里的元素是指针类型,然后再与int 结合,说明指针所指向的内容的类型是整型的,所以P 是一个由返回整型数据的指针所组成的数组
int (*p)[3]; //首先从P 处开始,先与*结合,说明P 是一个指针然后再与[]结合(与"()"这步可以忽略,只是为了改变优先级),说明指针所指向的内容是一个数组,然后再与int 结合,说明数组里的元素是整型的.所以P 是一个指向由整型数据组成的数组的指针
int **p; //首先从P 开始,先与*结合,说是P 是一个指针,然后再与*结合,说明指针所指向的元素是指针,然后再与int 结合,说明该指针所指向的元素是整型数据.由于二级指针以及更高级的指针极少用在复杂的类型中,所以后面更复杂的类型我们就不考虑多级指针了,最多只考虑一级指针.
int p(int); //从P 处起,先与()结合,说明P 是一个函数,然后进入()里分析,说明该函数有一个整型变量的参数,然后再与外面的int 结合,说明函数的返回值是一个整型数据
Int (*p)(int); //从P 处开始,先与指针结合,说明P 是一个指针,然后与()结合,说明指针指向的是一个函数,然后再与()里的int 结合,说明函数有一个int 型的参数,再与最外层的int 结合,说明函数的返回类型是整型,所以P 是一个指向有一个整型参数且返回类型为整型的函数的指针
int *(*p(int))[3]; //可以先跳过,不看这个类型,过于复杂从P 开始,先与()结合,说明P 是一个函数,然后进入()里面,与int 结合,说明函数有一个整型变量参数,然后再与外面的*结合,说明函数返回的是一个指针,,然后到最外面一层,先与[]结合,说明返回的指针指向的是一个数组,然后再与*结合,说明数组里的元素是指针,然后再与int 结合,说明指针指向的内容是整型数据.所以P 是一个参数为一个整数据且返回一个指向由整型指针变量组成的数组的指针变量的函数.
int GpioPolledExample(u16 DeviceId, u32 *DataRead)
u32 *DataRead 是一个指向32位无符号整数的指针,通过指针,函数可以直接访问和修改调用者提供的变量。
int GpioPolledExample(UINTPTR BaseAddress, u32 *DataRead) {
// 检查输入参数是否有效
if (DataRead == NULL) {
return -1; // 返回错误代码,表示无效的指针
//空指针表示该指针不指向任何有效的内存地址
}
// 从GPIO寄存器读取数据
u32 Data = READ_REGISTER(BaseAddress);
// 将读取到的数据存储到DataRead指向的地址
*DataRead = Data;
//DataRead 本身是个指针。*DataRead即表示那一块具体的内存
return 0; // 返回成功
}
—————————————————分界线—————————————————
———————————————————分界线—————————————————
——————————————————分界线——————————————————
void increment(int* ptr) {
if (ptr != NULL) {
(*ptr)++; // 通过指针修改变量的值
}
}
int* ptr 表示 ptr 是一个指向 int 类型的指针。
(*ptr)++ 表示通过指针解引用访问变量的值,并将其加1。
int main() {
int value = 10; // 定义一个变量
increment(&value); // 传递变量的地址
printf("Value after increment: %d\n", value); // 输出:11
return 0;
}
&value 获取变量 value 的地址,并将其传递给 increment 函数。
在 increment 函数中,通过指针修改了 value 的值。
#include <stdio.h>
int main() {
int value = 10; // 定义一个整数变量 value
int* p = &value; // 声明一个指针 p,并让它指向 value 的地址
printf("Value of value: %d\n", value); // 输出 value 的值
printf("Address of value: %p\n", &value); // 输出 value 的地址
printf("Value of p: %p\n", p); // 输出指针 p 的值(即 value 的地址)
printf("Value pointed by p: %d\n", *p); // 输出指针 p 所指向的值(即 value 的值)
return 0;
}
————————————————分界线———————————————
ConfigPtr->BaseAddr 不是一个指针,而是一个通过指针访问的结构体成员。具体来说,ConfigPtr 是一个指向结构体的指针,而 BaseAddr 是该结构体中的一个成员。通过 -> 运算符,你可以访问指针所指向的结构体中的成员。
————————————————分界线————————————————
void increment(int *ptr) {
(*ptr)++;
}
void wrapper(int *ptr) {
increment(&ptr); // 此处是错误的
}
在 wrapper 函数中,ptr 是一个指向 int 的指针( int *ptr
)。当你调用 increment(&ptr) 时,&ptr 获取的是 ptr 指针本身的地址,而不是 ptr 指向的 int 类型变量的地址。因此,increment 函数接收到的参数类型是 int**
,而不是它期望的 int*
。这会导致类型不匹配,进而引发未定义行为(如段错误或数据损坏)。
正确示例:
直接将 ptr 传递给 increment 函数,因为 ptr 已经是一个指向 int 的指针,正是 increment 函数期望的参数类型。
void increment(int *ptr) {
(*ptr)++; // 通过指针修改变量的值
}
void wrapper(int *ptr) {
increment(ptr); // 直接传递指针
}
int main() {
int value = 10;
wrapper(&value); // 将变量的地址传递给 wrapper
printf("Value: %d\n", value); // 输出 11
return 0;
}
————————————————分界线————————————————
void IntrHandler(void *CallBackRef, u32 Bank, u32 Status)
{
//将 CallBackRef 参数强制转换为 XGpioPs 类型的指针,并将其赋值给变量 Gpio
XGpioPs *Gpio = (XGpioPs *)CallBackRef;
u32 DataRead;
}
CallBackRef:
- CallBackRef 是一个
void*
类型的指针,通常作为中断处理函数的参数传递。它是一个通用指针,可以指向任何类型的数据。 - 在中断处理函数中,CallBackRef 通常用于传递与中断相关的上下文信息,例如硬件设备的驱动实例。
类型转换:
(XGpioPs *)
是一个强制类型转换操作符,将 CallBackRef 从void*
类型转换为XGpioPs*
类型。- 这种转换是必要的,因为
void*
是一个通用指针类型,不能直接用于访问特定类型的成员或调用特定类型的方法。
Gpio:
- Gpio 是一个指向 XGpioPs 类型的指针变量,用于存储转换后的指针。 在后续代码中,Gpio 可以被用来访问 XGpioPs类型的实例,例如调用其方法或访问其成员变量。