例如,給定一個函式
void func(const int* a, int* b){
*b = 2 *a;
}
如果 func 經常被這樣呼叫,我應該發出 const 嗎:func(ptr, ptr)?
uj5u.com熱心網友回復:
函式定義中的詞const表明函式不會更改地址作為第一個引數傳遞給函式的物件。它說這a是一個指向“常量整數”的指標。
因此,如果您的函式不更改a指向的物件,則保留const.
雖然沒有必要包括const,但這樣做是一種很好的做法。如果您不打算更改a指向的物件,但您的代碼無論如何都嘗試修改*a,這應該是您的編譯器將檢測到的錯誤。
uj5u.com熱心網友回復:
簡短的回答:
如果函式應該在兩個引數中使用相同的指標呼叫,則不應使用const. 否則,如果函式不支持兩個引數相同并且a不應該修改哪些點,則const應該作為“常量正確性”的一部分存在。
長答案:
const不保證指標是唯一別名。相反,取消參考 aconst int*被允許成為取消參考 an 的別名,int*作為所謂“嚴格別名規則”的例外之一,請參閱 C17 6.5 下方的例外串列:
物件的存盤值只能由具有以下型別之一的左值運算式訪問:
...
- 與物件的有效型別兼容的型別的限定版本
在實踐中,請查看以下示例:
#include <stdio.h>
void func(const int* a, int* b)
{
int tmp = *a;
printf("%d\n", tmp);
*b = 2 *a;
tmp = *a;
printf("%d\n", tmp);
}
int main (void)
{
int x = 1;
int* ptr=&x;
func(ptr,ptr);
printf("%d\n",*ptr);
}
使用 gcc 11.2 或 clang 14.0.0 x86_64 編譯-O3,列印:
1
3
3
也就是說,tmp由于編譯器無法假定左值*a未被先前的代碼修改,因此重新加載了 in 的值。
如果我們將此代碼更改為:
void func(const int* restrict a, int* b)
然后輸出變成:
1
1
3
restrict是編譯器和程式員之間的契約,所有對a指向的內容的訪問都通過指標a。由于編譯器現在可以自由假設a并且b不使用別名,因此它可以優化該tmp = *a;行,因為tmp已經包含*a.
在這個特定的例子中,程式員通過呼叫函式來欺騙編譯器,因為func(ptr,ptr)盡管引數被restrict編輯并且在函式內部列印 1 的意外結果是呼叫者代碼引起的錯誤。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/462780.html
上一篇:斷言指標與某個值對齊
