簡體   English   中英

有沒有一種方法可以使用const變量來初始化const結構?

[英]Is there a way to initialize a `const` `struct` using `const` variables?

我想在C99中創建一個struct ,該struct封裝一個以空終止的字符串緩沖區以及實際的字符串長度:

typedef unsigned int uint_t;
typedef unsigned char uchar_t;

typedef struct {
    uchar_t * buffer;
    uint_t length; // excluding null-terminating character
} string_t;

但是,我在旋轉struct成員的const時遇到了一些困難。 具體來說,當我想使用一個接受這樣的const struct string_tconst struct string_t ,並向其提供帶有const成員的初始化程序時,編譯器const struct string_t大叫。

void show_string_internal(const string_t str) {
    printf("%s", str.buffer);
}
void show_string(const uchar_t * buffer, uint_t length) {
    const string_t str = // <== tricky assignment here
        (const string_t){ buffer, length }; 
    show_string_internal(str);
}
int main() {
    uchar_t message[] = "Hello, world.";
    show_string(message, sizeof(message) - 1);
    return 0;
}

這會在GCC ...中的突出顯示的行上產生警告:

警告:初始化會從指針目標類型中丟棄“ const”限定符

...並在Visual Studio 2015中:

警告C4090:“正在初始化”:不同的“ const”限定詞

顯然,我在這里做錯了。 我發現解決此問題的唯一方法是聲明:

typedef struct {
    const uchar_t * buffer;
    const uint_t length;
} const_string_t;

但是現在我有兩種類型,而不是一種,所以我需要創建方便的方法來在兩種類型之間進行轉換,而且我正在創建聲明性糖而不是使用語言功能,因此代碼的可讀性較低。

所以我的問題是,正如標題所示:是否有一種方法可以為成員使用const變量來初始化const struct 是否有其他方法可以達到我希望達到的結果? 如果不是,為什么不這樣做(請提供對官方文件的引用)?

任何幫助,將不勝感激。

關於指針類型的常量應該從右到左讀取(而"const T * buffer" ”實際上是“指向常量內容的指針”,而不是“指向內容的常量指針”或“指向常量內容的常量指針”)。

因此,您將使用可變指針指向const char緩沖區,並將其用於結構的const版本(詢問具有可變字段的const結構-這是顯示警告的原因)。 如果您打算擺脫警告,則必須移動“ const”這樣的內容:

void show_string(char * const buffer, const int length) { // <== move const to the right of "*"
    const string_t str = // <== tricky assignment here
        (const string_t) {
        buffer, length
    };
    show_string_internal(str);
}

如果您還打算自己使用const緩沖區,則必須重新定義string_t結構(或作為單獨的類型引入):

typedef struct {
    const uchar_t * buffer; // <== add "const" here
    uint_t length; // excluding null-terminating character
} string_t;
...
void show_string(const char * const buffer, const int length) { // two "const" clauses there
    const string_t str = // <== tricky assignment here
        (const string_t) {
        buffer, length
    };
    show_string_internal(str);
}

希望這可以幫助。

問題不在結構級別。 問題在於使用char const*初始化.bufferunsigned char* )。 如果您使.buffer char const* ,則即使不進行強制轉換也可以使用,盡管由於簽名不同,您仍然會收到-Wall警告。

您的結構體具有聲明為uchar_t *buffer的成員,並且您嘗試使用聲明為const char *buffer的參數對其進行了初始化。 因此編譯器會抱怨,因為這樣會刪除 buffer指向的內存的預設常數(這種違反是邏輯錯誤)。 根據您的需求/意願,您可以:

  1. 將參數傳遞為非常量,
  2. 作為const傳遞,但隨后在結構中將成員聲明為const,
  3. 使用復制語義並為成員分配一些內存,然后將參數指向的值復制到成員指向的內存。

還請注意uchar_tchar可能不是同一類型...

正如其他人所寫的那樣,問題與const類型限定符影響struct聚合類型的方式有關。 所有的struct成員值本身都是const 對於指針成員,這僅意味着您不能更改指針變量,使其指向其他任何位置,但是指針指向的任何內容仍然可變。 這類似於如果聲明一個int * const變量將發生的情況。

似乎是在C99沒有辦法賦予const的是所謂的聚合類型的部分間接(指針)類型的目標-ness。 因此,無法將關鍵字附加到struct type變量以表示其指針成員應被視為指向const類型的指針,例如int const * 僅在第6.7.3節(類型限定符)末尾的C99C11標准中均以示例方式提及。

該答案是基於Yuval和PSkocik之間對Jean-BaptisteYunès的回答的對應關系而得出的。

這只是錯誤的常數:

typedef unsigned int uint_t; typedef unsigned char uchar_t;

使用正確的尺寸類型。 在C中是size_t

typedef struct {
    const uchar_t * buffer;
    size_t length; // excluding null-terminating character
} string_t;

void show_string(const uchar_t * buffer, size_t length) {
    const string_t str = // <== tricky assignment here
        (string_t){ buffer, length }; 
} 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM