回调函数、函数绝对地址跳转、函数数组指针

学习记录下。。。。。。。。。。。。。 

/************************************************************************ 
 * @  自学习记录一下
 * 
 * 
 ************************************************************************/
#if 1
/* 回调函数简单示例
 * typedef void (*lpFunction)();
 * lpFunction lpreset = (lpFunction)(0xF000FFF0)
 * lpreset();
#######函数绝对地址条跳转
######## tyepdef 形式
	lpFun fun = (lpFun)&get_memory;
	fun();
######## 普通指针函数形式
	void (*pFun)();
	pFun = (void (*)())&get_memory;
	pFun();
########  一步直接跳转形式
	(*(void (*)())(&get_memory))();
	((void (*)())&get_memory)();
	
注意:
	void aCal(void *param, void *func)
	{
		((void (*)(void *))func)(param)
	}

*/

#if 0
/***************************************
 * @ 简单回调函数
 * 
 ***************************************/

typedef int (*pFun)(int *, int *, int *);

int call_back(int *a, int *b, int *c)
{
	*c = *a + *b;
	printf("c = %d\n", *c);
	printf("%s\n", __func__);
}

void call_back1(int *a, int *b, int *c)
{
	*c = *b - *a;
	printf("c1 = %d\n", *c);
	printf("%s\n", __func__);
}

int call_pFun(int *a, int *b, int *c, pFun call_fun)
{
	pFun plus = call_fun;
	plus(a, b, c);
}

int main()
{
	int a = 1;
	int b = 2;
	int c = 0;
	//利用 typedef
	call_pFun(&a, &b, &c, call_back);
	//普通函数指针
	void (*pFun1)(int *, int *, int *);
	pFun1 = call_back1;
	pFun1(&a, &b, &c);

	return 0;
}
#endif

/***************************************
 * @ 程序绝对地址的跳转
 * 
 ***************************************/
typedef void (*lpFun)(void);

void get_memory(void)
{
	int k = 0, b = 4;
	printf("I am Here!\n");
}

int main(void)
{
	unsigned int p;
	printf("%#x\n", &get_memory);

	// tyepdef 形式
	lpFun fun = (lpFun)&get_memory;
	fun();
	// 定义指针函数形式
	void (*pFun)();
	pFun = (void (*)())&get_memory;
	pFun();
	// 直接跳转形式
	(*(void (*)())(&get_memory))();
	((void (*)())&get_memory)();// 等价于 ((void (*)())(&get_memory))();
	((lpFun)(&get_memory))();// 等价于 ((lpFun)get_memory)();
	
	return 0;
}

#endif

/***************************************
 * @ 函数数组指针实现 1
 * 
 ***************************************/
#include <stdio.h>
#include <stdlib.h>

typedef int (test_fun_t)(void);

int plus(void)
{
	printf("plus\n");
}

int sub(void)
{
	printf("sub\n");
}

test_fun_t *init_seq[] = {
	plus,
	sub,
	NULL,
};

int main()
{
	test_fun_t **fun_seq = NULL;
	int i = 0;

	for (fun_seq = init_seq; *fun_seq; fun_seq++) {
		if ((*fun_seq)(void) != 0) {
			perror("error");
		}
		sleep(1);
	}

	return 0;
}


/***************************************
 * @ 函数数组指针实现 2
 * 
 ***************************************/
typedef int (*test_fun_t)(void);

int plus()
{
        printf("plus\n");
        return 0;
}

int sub()
{
        printf("sub\n");
        return 0;
}

test_fun_t init_seq[] = {
	plus,
	sub,
	NULL
};

int main()
{
        test_fun_t *fun_seq = NULL;

        for (fun_seq = init_seq; *fun_seq; fun_seq++) {
			if ((*fun_seq)() != 0) {
				perror("error");
			}
        }

        return 0;
}

/***************************************
 * @ 函数数组指针实现(带参数) 3
 * 
 ***************************************/
typedef int (*test_fun_t)(int *, int *);

static a = 1, b = 2;
int plus(int *a, int *b)
{
        printf("plus = %d\n", *a + *b);
        return 0;
}

int sub(int *a, int *b)
{
        printf("sub = %d\n", *b - *a);
        return 0;
}

test_fun_t init_seq[] = {
	plus,
	sub,
	NULL
};

int main()
{
        test_fun_t *fun_seq = NULL;

        for (fun_seq = init_seq; *fun_seq; fun_seq++) {
			if ((*fun_seq)(&a, &b) != 0) {
				perror("error");
			}
        }

        return 0;
}




/*******************************
 * 注意: void * 应用
 *****************************/
void sCal(void *param, void *func)
{
    ((void (*)(void *))func)(param);
}


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

typedef struct {
	int a;
	int b;
	int result;
}sAdd;

typedef struct {
	float a;
	float b;
	float result;
}sMul;

void Add(void *param)
{
	sAdd *p = (sAdd *)param;
	p->result = p->a + p->b;
}

void Mul(void *param)
{
	sMul *p = (sMul *)param;
	P->result = p->a * p->b;
}

void sCal(void *func, void *param)
{
	((void (*)(void *))func)(param);
}

int main()
{
	sAdd stAdd = {0};
	sMul stMul = {0};

	stAdd.a = 10;
	stAdd.b = 20;

	stMul.a = 5;
	stMul.b = 5;

	sCal(Add, &stAdd);
	sCal(Mul, &stMul);

	printf("a + b = %d\n", stAdd.result);
	printf("a * b = %f\n", stMul.result);

	return 0;
}

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

#define AVDD_NAME		"avdd"
#define IOVDD_NNAME		"ioavvd"
#define FW_NAME			"goodix_firmware.bin"
#define CFG_BIN_NAME		"goodix_cfg_group.bin"

int short_threshold1[] = {500, 200, 300};

//struct goodix_ts_board_data {
//    int (*short_threshold)[3];
//};
//
//struct goodix_ts_board_data g_board_data = {
//    .short_threshold = &short_threshold1,
//};

struct goodix_ts_board_data {
	char avdd_name[32];
	char iovdd_name[32];
	int reset_gpio;
	int irq_gpio;
	int avdd_gpio;
	int iovdd_gpio;
	unsigned int  irq_flags;

	unsigned int swap_axis;
	unsigned int panel_max_x;
	unsigned int panel_max_y;
	unsigned int panel_max_w; /*major and minor*/
	unsigned int panel_max_p; /*pressure*/

	//bool pen_enable;
	//bool poweron_inspect_enable;
	char fw_name[32];
	char cfg_bin_name[32];

	/* [0]: Tx-Rx [1]: Trx-VDD [2]: Trx-GND */
	int (*short_threshold)[3];
};


static struct goodix_ts_board_data g_board_data = {
	.avdd_name = AVDD_NAME,
	.iovdd_name = IOVDD_NNAME,
	.reset_gpio =  35,
	.irq_gpio =  27,
	//.avdd_gpio =  ,
	//.iovdd_gpio = ,
	//.irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;;
	.irq_flags = 12,

	//.swap_axis = ,
	.panel_max_x = 2560,
	.panel_max_y = 1440,
	.panel_max_w = 255, /*major and minor*/
	.panel_max_p = 4096, /*pressure*/

	//bool pen_enable;
	//bool poweron_inspect_enable;
	//char *fw_name = "FW_NAME",
	//char *cfg_bin_name = CFG_BIN_NAME,
	.fw_name = "FW_NAME",
	.cfg_bin_name = CFG_BIN_NAME,

	/* [0]: Tx-Rx [1]: Trx-VDD [2]: Trx-GND */
	.short_threshold = &short_threshold1,
};
 
struct goodix_ts_board_data *g_ptr = &g_board_data;

int main()
{
	int i = 0;
	const char haystack[20] = "RUNOOB";
	//const char needle[10] = "NOOB";
	const char needle[10] = "OB";
	char *ret;
 
	ret = strstr(haystack, needle);

	printf("strstr: %s\n", ret);
	
//	for ( i = 0; i < 3; i++) {
//		//printf("g_board_info_%d = %d\n", i, *((g_board_data.short_threshold)[i]));
//		printf("g_board_info_%d = %d\n", i, (*g_board_data.short_threshold)[i]);
//	}
//
	for ( i = 0; i < 3; i++) {
		printf("g_ptr_%d = %#x\n", i, (unsigned char *)&(*g_ptr->short_threshold)[i]);
		printf("g_ptr_%d = %d\n", i, (*g_ptr->short_threshold)[i]);
	}

//具体数值
    // 打印数组元素的值
    for (int i = 0; i < 3; i++) {
        printf("Element %d: %d\n", i, (*g_ptr->short_threshold)[i]);
    }

    // 使用指针算术打印数组元素的值
    for (int i = 0; i < 3; i++) {
        printf("Element %d using pointer arithmetic: %d\n", i, *(*g_ptr->short_threshold + i));
    }

//值的存放地址
    // 打印数组元素的地址
    for (int i = 0; i < 3; i++) {
        printf("Address of Element %d: %p\n", i, (void *)&(*g_ptr->short_threshold)[i]);
    }

    // 使用指针算术打印数组元素的地址
    for (int i = 0; i < 3; i++) {
        printf("Address of Element %d using pointer arithmetic: %p\n", i, (void *)(*g_ptr->short_threshold + i));
    }

	printf("g_board_info.fw_name = %s\n", g_board_data.fw_name);
	printf("g_board_info.cfg_bin_name = %s\n", g_board_data.cfg_bin_name);
   
   return(0);
}

#if 0
```c
struct goodix_ts_board_data {
	// ... 其他成员 ...
	int (*short_threshold)[3];
};
```

在初始化时:
```c
int short_threshold1[] = {500, 200, 300,};

static struct goodix_ts_board_data g_board_data = {
	// ... 其他初始化 ...
	.short_threshold = &short_threshold1,
};
```

`short_threshold1` 是一个一维数组,它包含3个整数。当你使用`&short_threshold1`时,得到的是一个指向一维数组的指针,即`int (*)[3]`。

### 错误解引用

在你的`main()`函数中,你尝试这样打印数组的数据:
```c
for ( i = 0; i < 3; i++) {
	printf("g_board_info_%d = %d\n", i, *((g_board_data.short_threshold)[i]));
}

for ( i = 0; i < 3; i++) {
	printf("g_ptr_%d = %d\n", i, *(g_ptr->short_threshold[i]));
}
```
goodix_i2c_write(struct device *dev, unsigned int reg, unsigned char *data, unsigned int len)
brl_write(cd, INSPECT_THRESHOLD_REG_B2, (u8 *)&cd->board_data.short_threshold[0], 2);
brl_write(cd, INSPECT_THRESHOLD_REG_B2, cd->board_data.short_threshold[0], 2);

这两段代码都有问题,因为你将 `short_threshold` 当作一个指向指针数组的指针。

### 正确的访问方式

正确的访问方式是首先解引用`short_threshold`指针,然后访问数组元素:

```c
for (i = 0; i < 3; i++) {
    printf("g_board_info_%d = %d\n", i, (*g_board_data.short_threshold)[i]);
}

for (i = 0; i < 3; i++) {
    printf("g_ptr_%d = %d\n", i, (*g_ptr->short_threshold)[i]);
}
```











你的表达式 `(*g_ptr->short_threshold)[i])` 可能会让人困惑,因为它包含了多种运算符:
解引用运算符 `*`、箭头运算符 `->` 和数组下标 `[]`。为了更清晰地理解这一表达式,我们需要详细解析它。

### 背景示例

假设你有以下结构体和全局数组:

```c
#include <stdio.h>

int short_threshold1[] = {500, 200, 300};

struct goodix_ts_board_data {
    // 其他成员变量 ...
    int (*short_threshold)[3];
};

struct goodix_ts_board_data g_board_data = {
    // 初始化其他成员变量 ...
    .short_threshold = &short_threshold1,
};

struct goodix_ts_board_data *g_ptr = &g_board_data;
```

### 表达式解析

让我们逐步解析 `(*g_ptr->short_threshold)[i]`:

1. **`g_ptr->short_threshold`**
   - `g_ptr` 是指向 `goodix_ts_board_data` 结构体的指针。
   - `->` 运算符用于通过结构体指针访问成员变量。
   - `g_ptr->short_threshold` 结果是 `short_threshold` 成员变量的值,即指向 `short_threshold1` 的指针(类型为 `int(*)[3]`)。

2. **`*g_ptr->short_threshold`**
   - `g_ptr->short_threshold` 得到的是一个指向数组的指针。
   - `*` 运算符用于解引用这个指针。
   - 因此,`*g_ptr->short_threshold` 结果是 `short_threshold1` 数组的首地址(类型为 `int[3]`)。

3. **`(*g_ptr->short_threshold)[i]`**
   - `*g_ptr->short_threshold` 是 `short_threshold1` 数组。
   - `(*g_ptr->short_threshold)[i]` 访问 `short_threshold1` 数组的第 `i` 个元素。

### 总结

`(*g_ptr->short_threshold)[i]` 表达式通过 `g_ptr` 访问 `short_threshold` 指针,然后解引用该指针获取数组 `short_threshold1`,最后使用数组下标访问其中的第 `i` 个元素。
















当你通过指针 `g_ptr` 访问到 `short_threshold` 时,你实际上获得了一个指向 `short_threshold1` 数组的指针。
`*g_ptr->short_threshold` 的结果是 `short_threshold1` 数组本身(也就是数组的首地址)。
要访问 `short_threshold1` 数组的元素和它们的地址,可以使用指针算术和数组访问的技巧。

### 回顾:背景示例

假设有如下的结构体和全局数组定义:

```c
#include <stdio.h>

int short_threshold1[] = {500, 200, 300};

struct goodix_ts_board_data {
    int (*short_threshold)[3];
};

struct goodix_ts_board_data g_board_data = {
    .short_threshold = &short_threshold1,
};

struct goodix_ts_board_data *g_ptr = &g_board_data;
```

`g_ptr->short_threshold` 是一个指向 `short_threshold1` 数组的指针。`*g_ptr->short_threshold` 是解引用该指针,得到 `short_threshold1` 数组本身(也就是数组的首地址)。

### 访问和打印数组元素及其地址

你可以通过以下几种方式来访问和打印 `short_threshold1` 数组的元素及其地址:

#### 访问具体元素值

1. **直接通过解引用和数组下标访问元素值**

   ```c
   for (int i = 0; i < 3; i++) {
       printf("Element %d: %d\n", i, (*g_ptr->short_threshold)[i]);
   }
   ```
   
2. **使用指针算术访问元素值**

   ```c
   for (int i = 0; i < 3; i++) {
       printf("Element %d: %d\n", i, *(*g_ptr->short_threshold + i));
   }
   ```

#### 获取元素地址

1. **获取元素的地址**

   ```c
   for (int i = 0; i < 3; i++) {
       printf("Address of Element %d: %p\n", i, (void *)&(*g_ptr->short_threshold)[i]);
   }
   ```
让我们逐步解析 `(void *)&(*g_ptr->short_threshold)[i]`:

1. **`g_ptr->short_threshold`**
   - `g_ptr` 是指向 `goodix_ts_board_data` 结构体的指针。
   - `->` 运算符用于通过结构体指针访问成员变量。
   - `g_ptr->short_threshold` 是 `short_threshold` 成员变量的值,它是一个指向包含三个整数的数组的指针。

2. **`*g_ptr->short_threshold`**
   - 解引用 `g_ptr->short_threshold` 指针,得到的是 `short_threshold1` 数组本身。类型为 `int[3]`。

3. **`(*g_ptr->short_threshold)[i]`**
   - 首先解引用 `g_ptr->short_threshold` 得到 `short_threshold1` 数组。
   - 然后使用数组下标 `[i]` 访问 `short_threshold1` 数组的第 `i` 个元素。

4. **`&(*g_ptr->short_threshold)[i]`**
   - 获取 `(*g_ptr->short_threshold)[i]` 表达式的地址,这里 `&` 运算符用于取得第 `i` 个元素的地址。

5. **`(void *)&(*g_ptr->short_threshold)[i]`**
   - 通过 `(void *)` 将地址类型转换为 `void *`。这在需要通用指针类型时很有用,例如在需要将指针传递给接受 `void *` 参数的函数时。

2. **使用指针算术获取元素地址**

   ```c
   for (int i = 0; i < 3; i++) {
       printf("Address of Element %d: %p\n", i, (void *)(*g_ptr->short_threshold + i));
   }
   ```

### 示例代码

以下是完整的代码示例,展示如何访问数组元素及其地址:

```c
#include <stdio.h>

int short_threshold1[] = {500, 200, 300};

struct goodix_ts_board_data {
    int (*short_threshold)[3];
};

struct goodix_ts_board_data g_board_data = {
    .short_threshold = &short_threshold1,
};

struct goodix_ts_board_data *g_ptr = &g_board_data;

int main() {
    // 打印数组元素的值
    for (int i = 0; i < 3; i++) {
        printf("Element %d: %d\n", i, (*g_ptr->short_threshold)[i]);
    }

    // 使用指针算术打印数组元素的值
    for (int i = 0; i < 3; i++) {
        printf("Element %d using pointer arithmetic: %d\n", i, *(*g_ptr->short_threshold + i));
    }

    // 打印数组元素的地址
    for (int i = 0; i < 3; i++) {
        printf("Address of Element %d: %p\n", i, (void *)&(*g_ptr->short_threshold)[i]);
    }

    // 使用指针算术打印数组元素的地址
    for (int i = 0; i < 3; i++) {
        printf("Address of Element %d using pointer arithmetic: %p\n", i, (void *)(*g_ptr->short_threshold + i));
    }

    return 0;
}
```

### 运行结果

运行上述代码,输出将会类似如下:

```
Element 0: 500
Element 1: 200
Element 2: 300
Element 0 using pointer arithmetic: 500
Element 1 using pointer arithmetic: 200
Element 2 using pointer arithmetic: 300
Address of Element 0: 0x7ffc0c1d85a0
Address of Element 1: 0x7ffc0c1d85a4
Address of Element 2: 0x7ffc0c1d85a8
Address of Element 0 using pointer arithmetic: 0x7ffc0c1d85a0
Address of Element 1 using pointer arithmetic: 0x7ffc0c1d85a4
Address of Element 2 using pointer arithmetic: 0x7ffc0c1d85a8
```

以上的代码和输出展示了如何通过结构体指针访问数组元素及其地址。希望这些示例有助于你理解和应用。如果有任何其他问题,请随时提问。







### 示例代码

下面是完整的代码示例,演示如何使用这个表达式访问数组元素并打印出来:

```c
#include <stdio.h>

int short_threshold1[] = {500, 200, 300};

struct goodix_ts_board_data {
    // 其他成员变量 ...
    int (*short_threshold)[3];
};

struct goodix_ts_board_data g_board_data = {
    // 初始化其他成员变量 ...
    .short_threshold = &short_threshold1,
};

struct goodix_ts_board_data *g_ptr = &g_board_data;

int main() {
    for (int i = 0; i < 3; i++) {
        printf("Element %d: %d\n", i, (*g_ptr->short_threshold)[i]);
    }
    return 0;
}
```

### 输出

运行上述代码,输出将是:

```
Element 0: 500
Element 1: 200
Element 2: 300
```

### 特别注意

- 确保 `short_threshold` 指针正确地指向一个包含3个整数的一维数组。
- 确保 `(*g_ptr->short_threshold)[i]` 中的 `i` 不超过数组的边界。

理解这些运算符及其优先级,可以帮助你更清楚地编写和调试C语言代码。如果你有其他问题,请随时提问。



在C语言中,符号(运算符)的优先级决定了表达式的求值顺序。了解这些优先级对于正确编写和调试代码至关重要。下面是一个详细的运算符优先级表,从最高优先级到最低优先级,包括每个运算符的结合性(从左到右或从右到左)。

### 运算符优先级表

1. **后缀表达式**
   - **运算符**:`()`(函数调用), `[]`(数组下标), `.`(结构成员访问), `->`(指向结构成员的指针访问), `++`(后置增量), `--`(后置减量)
   - **结合性**:从左到右

2. **一元运算符**
   - **运算符**:`+`(正号), `-`(负号), `!`(逻辑非), `~`(按位非), `++`(前置增量), `--`(前置减量), `*`(解引用), `&`(取地址), `sizeof`(大小)
   - **结合性**:从右到左

3. **类型转换(类型名)**
   - **运算符**:`(type)`
   - **结合性**:从右到左

4. **乘除和取余**
   - **运算符**:`*`(乘法), `/`(除法), `%`(取余)
   - **结合性**:从左到右

5. **加减**
   - **运算符**:`+`(加法), `-`(减法)
   - **结合性**:从左到右

6. **移位**
   - **运算符**:`<<`(左移), `>>`(右移)
   - **结合性**:从左到右

7. **关系运算符**
   - **运算符**:`<`(小于), `<=`(小于等于), `>`(大于), `>=`(大于等于)
   - **结合性**:从左到右

8. **相等性运算符**
   - **运算符**:`==`(等于), `!=`(不等于)
   - **结合性**:从左到右

9. **按位与**
   - **运算符**:`&`
   - **结合性**:从左到右

10. **按位异或**
    - **运算符**:`^`
    - **结合性**:从左到右

11. **按位或**
    - **运算符**:`|`
    - **结合性**:从左到右

12. **逻辑与**
    - **运算符**:`&&`
    - **结合性**:从左到右

13. **逻辑或**
    - **运算符**:`||`
    - **结合性**:从左到右

14. **条件运算符**
    - **运算符**:`? :`
    - **结合性**:从右到左

15. **赋值运算符**
    - **运算符**:`=`, `+=`, `-=`, `*=`, `/=`, `%=`, `<<=`, `>>=`, `&=`, `^=`, `|=`
    - **结合性**:从右到左

16. **逗号运算符**
    - **运算符**:`,`
    - **结合性**:从左到右

### 示例代码

通过示例了解运算符的优先级和结合性是非常有帮助的。以下是一些示例代码:

1. **后缀表达式和一元运算符**

   ```c
   int a = 5;
   int b = a++; // b = 5, a = 6(后置增量)
   int c = ++a; // a = 7, c = 7(前置增量)
   ```

2. **类型转换和乘除**

   ```c
   float d = (float)5 / 2; // d = 2.5(类型转换优先级高于除法)
   ```

3. **加减和移位**

   ```c
   int e = 3 + 5 << 2; // e = 3 + (5 << 2) = 3 + 20 = 23(移位优先级高于加法)
   ```

4. **关系运算符和相等性运算符**

   ```c
   int f = 5 > 3 == 1; // f = (5 > 3) == 1 = 1 == 1 = 1(关系运算符优先级高于相等性运算符)
   ```

5. **按位与和逻辑与**

   ```c
   int g = 1 & 1 && 0; // g = (1 & 1) && 0 = 1 && 0 = 0(按位与优先级高于逻辑与)
   ```

6. **条件运算符和赋值运算符**

   ```c
   int h = (a = 3) ? 5 : 6; // h = 5(赋值运算符优先级低于条件运算符)
   ```

7. **逗号运算符**

   ```c
   int i = (a = 2, b = 3); // i = 3(逗号运算符优先级最低)
   ```

### 总结

理解运算符的优先级和结合性可以帮助你避免常见的编程错误,并使你更容易阅读和理解代码。如果你对特定运算符的行为或优先级有疑问,参考运算符优先级表或添加必要的括号来明确表达式的求值顺序。这样能让你的代码更加清晰和易于维护。

#endif


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值