我已經被告知如果我在ANSI-C中編寫聲明變量將被使用的順序,聲明指針不爲空,並且索引在邊界,並在變量使用之前進行初始化。C:`const`關鍵字的行爲
如果我聲明一個const,我可以在斷言和代碼塊之後初始化它嗎? 在Java中,最終的初始化必須發生在聲明處,但它是否通過ANSI-C實現是一致的,我可以初始化一個const,但不一定在聲明時初始化?
我已經被告知如果我在ANSI-C中編寫聲明變量將被使用的順序,聲明指針不爲空,並且索引在邊界,並在變量使用之前進行初始化。C:`const`關鍵字的行爲
如果我聲明一個const,我可以在斷言和代碼塊之後初始化它嗎? 在Java中,最終的初始化必須發生在聲明處,但它是否通過ANSI-C實現是一致的,我可以初始化一個const,但不一定在聲明時初始化?
Java編譯器有少量的流程邏輯允許您在聲明後初始化變量final
。這是合法的Java:
final int something;
if (today == Friday)
something = 7;
else
something = 42;
Java將檢測是否有任何分支離開最終值undefined。它不會分析的條件,所以這是不合法的Java,即使它的邏輯類似:
final int something;
if (today == Friday)
something = 7;
if (today != Friday)
something = 42;
在ANSI C89,const
變量(比extern
除外)必須在它們的聲明語句被初始化。
const int something = (today == Friday) ? 7 : 42;
的extern
改性劑上的聲明告訴該變量在不同的complation單元(在該編譯單元或其他地方)初始化的編譯器。
在ANSI C99中,您可以混合使用聲明和代碼,因此您可以在斷言和代碼塊之後聲明並初始化一個const
變量。 1999 ANSI C的可移植性仍然是一個問題。
用於C89的解決辦法是要注意,對於代碼的工作之前在塊範圍而不是函數範圍,所以你可以做這個聲明的規則:
#include<stdio.h>
int main (void)
{
printf ("wibble\n");
{
const int x = 10;
printf ("x = %d\n", x);
}
return 0;
}
const
變量是隻讀的,必須在定義它們的位置進行初始化。
這段代碼產生error: assignment of read-only variable 'foo'
(GCC4):
const int foo;
foo = 4;
同去的常量指針(注意這裏:const int *
不是一個常量指針,但指針常數):
int * const foo;
foo = 4;
最後一個例子是否需要* foo = 4;生成錯誤?因爲分配4只會使用不可能的指針值... – 2009-09-13 11:29:52
取決於您的意思。 'foo = 4'是一個編譯錯誤,因爲foo是const。 '* foo = 4'是一個運行時錯誤(希望編譯時警告),因爲foo是未初始化的(或者如果是全局的,則初始化爲NULL)。 – 2009-09-13 12:31:13
如果你正在談論分裂定義
const int x = 2;
成兩個部分:
const int x;
x=2;
恐怕這是不可能的C.
如果我是你,我會嘗試,以確保我的理解,你描述的編碼規則的意圖。我懷疑明智的編碼規則會阻止初始化變量(即使是非const變量)。
響應於各種評論:
const int * p;
不是一個常量變量的聲明。它是一個const const的非const指針變量的聲明。
你可以聲明
extern const int x;
但在已執行的代碼,斷言檢查,之後你仍然不能初始化X ...
+1。 「初始化在使用之前初始化」的意圖可能是(1),使得初始值在物理上接近於依賴它的代碼,和/或(2)如果初始化確實有效,有時可以避免,首先使用的是最好的經驗法則來最大限度地避免它的可能性。所以你必須衡量這兩個東西與標記爲const的值。 – 2009-09-13 10:43:04
是的,我花了Pavel Shved的回答才意識到問題可能與本地const變量有關。我一直在考慮全局變量。 – 2009-09-13 10:48:48
你不能在函數體內聲明後,初始化常量,但您可以斷言後只需打開一個塊:
void func()
{
int y;
//do assertions
assert(something);
{
int const x = 5;
// function body
}
}
要知道,即使是在C89,你可以經常移動的定義更接近於由introduci首先使用點只爲額外的範圍提供一個裸塊。之前:
int a, b, c;
a = 12;
// do some stuff with a
b = 17;
// do some stuff with a and b
c = 23;
// do some stuff with a, b, and c
後:
int a = 12;
// do some stuff with a
{
int b = 17
// do some stuff with a and b
{
int c = 23;
// do some stuff with a, b and c
}
}
當然了C99,您可以定義其他變量不是在塊的開頭:
int a = 12;
// do some stuff with a
int b = 17
// do some stuff with a and b
int c = 23;
// do some stuff with a, b and c
短塊範圍和C99申報方法其他人已經表明,答案是否定的;你不能推遲const變量的初始化。無論如何,const對局部變量不是很有用。我在C中使用const關鍵字的主要時間是:
我有時會聲明局部變量const,如果我認爲它會幫助讀者理解函數,但這很少見。
如果你想在LHS上拋棄const,那麼這個怎麼樣?
const int n = 0;
*((int*)&n) = 23;
這個怎麼樣?非常糟糕的主意。它繞過了語言決定實施的限制。甚至可能導致錯誤,具體取決於您的編譯器實現。 – einpoklum 2015-11-19 09:39:12
@Pete:2x經驗教訓。 – 2009-09-13 10:58:59
實際上,你可以在不初始化的情況下聲明非extern const * global *變量。 'const int a;'被稱爲「暫定義」,或類似的東西。如果變量稍後被明確定義,那麼它就被視爲一個聲明。如果不是,這是一個定義。所以你可以在頭文件中包含'const int a;',然後在.c文件中包含'const int a = 12;'。不是你經常會想要的,因爲你可能會忘記定義,並且在某些編譯單元中爲'a'爲12,而在其他編譯單元中爲0 ... – 2009-09-13 11:13:18
@onebyone:實際上,「暫定義」不會導致不同值在不同的編譯單元中。嘗試編譯「int x;」在一個文件中並且「int x = 1;」在另一個。變量x在鏈接後包含兩個文件(包括我試過的所有編譯器)。這是廣泛實施的行爲,雖然我沒有閱讀C99作爲具體說明。 – 2009-09-13 11:25:51