1. 程式人生 > 其它 >[C語言低能兒]函式瘋裝進階-static與函式指標

[C語言低能兒]函式瘋裝進階-static與函式指標

static關鍵字

印象中以前C語言老師沒有把static講全,只是簡單講了static用於修飾區域性變數。
但是在後續的學習過程中,發現static並非僅有一種用法。

作用於區域性變數

這是很多人常用的了
在任意一個函式內部定義的變數(不加static),其初始值不確定,並存放於棧區,出了這個函式就不能確定其值。
而對於用static修飾的區域性變數,編譯器會將其初始化為零,和全域性變數一同儲存,並且static所在的語句只會執行一次。

作用於全域性變數

全域性變數定義於函式體外部,對於全工程都可見,其他檔案使用關鍵字extern宣告之後即可使用。
但是如果在其前面新增static關鍵字,那麼該靜態全域性變數將僅對當前檔案可見,其他檔案不可訪問。

作用於函式

和作用於全域性變數類似的,靜態函式只能在宣告它的檔案可見,其他檔案不能引用該函式。

對於封裝的益處

使用static變數後,我們可以將我們自己函式庫封裝中的一些不希望外部呼叫的函式和變數隱藏起來,同時如果外部定義了同名的函式或者變數,編譯器也不會報錯


如果像是這麼寫的話,在庫外面就不能再定義a這個變量了,如果進行編譯會出現如下報錯:

foriver@DESKTOP-T9PMSMI:~/code/C/staticNfun$ gcc main.c staticvar.c -I .
/usr/bin/ld: /tmp/cc0WGFQn.o:(.bss+0x0): multiple definition of `a'; /tmp/cce6Zp1k.o:(.data+0x0): first defined here
collect2: error: ld returned 1 exit status

但是如果在a前面新增static修飾的話就沒有問題了

當然函式方面也是同理。

函式指標

很多時候底層的函式各有各的不同,比如STM32的HAL庫需要修改GPIO的電平值需要三個引數,但是有的微控制器的sdk裡寫的就可能只需要兩個引數。
如果想要寫一個上層庫去做封裝的話,不得不把移植性考慮進去。
那能這一次寫好了在32的版本,下一次移植到其他平臺上就要進到庫裡一句一句的改吧?
怎麼去讓自己的封裝更加的靈活呢,這裡就會用到函式指標了。

實際上如果你去閱讀HAL庫這種比較成熟的庫會發現有很多使用函式指標的地方。

宣告規則

例子:
void *fun(void *param)這裡fun是一個指向函式的指標,同時它有一個void指標作為入口引數

可以自行查閱資料,另外這是我之前的總結
https://www.cnblogs.com/Foriver/p/15888594.html

使用例

筆者在之前進行小車配合mpu6050yaw角控制方向的時候,遇到過因為yaw角範圍限定在-180~180導致pid計算出現問題的情況

我這裡想到的一個解決方法是修改yaw角的加法法則,把關於yaw角的加減計算替換成自己的加法法則,這樣就能一次性的解決:

float yaw_calc_plus(float num1, float num2)
{
	float res = num1 + num2;
	if (res > 180)
		res = res - 360;
	else if (res < -180)
		res = 360 + res;
	return res;
}

當時遇到一個問題就是我的pid已經封裝好了,但是關於誤差的運算也需要替換加法法則,怎麼辦呢,總不能再寫一個pid吧?(如果你看過我的程式碼的話會發現我真的這麼幹了)
這裡我就想到了使用函式指標:
在pid結構體中加入這麼一個成員:

float (*pid_add_f)(float a,float b);

在普通的pid計算中我們將其賦值為NULL,當想要替換加法法則時則可以將其賦值為我們想呼叫的函式,下面就是我這次智慧車比賽的程式碼片段:

PID_AddFuncSet(&yawpid, &yaw_add_fun);//這是設定時呼叫的函式

void PID_AddFuncSet(PID_t *pid, float (*pid_add_f)(float a, float b))
{
	pid->pid_add_f = pid_add_f;
}

在pid計算中就只需要稍微修改就可以:

if (pid->pid_add_f != NULL)
	pid->err = pid->pid_add_f(target, -current);//添一個負號就是減法
else//如果指標為NULL那就執行正常的減法
	pid->err = target - current;