簡體   English   中英

是否可以更改 C 中的 const 結構成員?

[英]Is it possible to change a const struct member in C?

我必須在 C 中更改 const struct 實例的 const 成員。

我已經知道可以按如下方式更改 const 基本類型:

const int a = 2;
*(int*)&a = 3;

我還可以更改結構實例的 const 成員,如下所示:

typedef struct ST {
  const int a;
  const int b;
}ST;
ST st = {.a = 1,.b =2};

int main() {
    *(int *)(&((*(ST*)(&st)).a)) = 5; //works fine , no problem
}

但是,如果實例是常量,我嘗試更改結構實例的 const 成員沒有成功:

typedef struct ST {
  const int a;
  const int b;
}ST;

const ST st = {.a = 2,.b=3}; //const instance

int main() {
    *(int *)(&((*(ST*)(&st)).a)) = 5; //does not work(Seg fault)!!
}

那么,在最后一種情況下是否可以更改“a”成員值? 如果不是,為什么?

我已經知道可以按如下方式更改 const 基本類型:

 const int a = 2; *(int*)&a = 3;

您的編譯器允許您這樣做的事實並不使其合法。 此代碼調用未定義的行為,因此如果您在不同的平台上運行相同的程序或使用不同的編譯器,它可能會失敗或崩潰。

 *(int *)(&((*(ST*)(&st)).a)) = 5; //works fine , no problem

這段代碼有同樣的問題:它調用了未定義的行為。

您嘗試的最后一段代碼也有(您猜對了!)未定義的行為。 然而,這一次,程序崩潰而不是運行完成。

C 編譯器通常將常量放在只讀內存段中,通常稱為 .TEXT 或 .CODE。 該段(內存塊)受到操作系統寫入保護,或者對於小型嵌入式 CPU 和 SoC 常量通常與代碼一起放置在 ROM/或閃存中。 不建議您嘗試執行此操作,因為它會影響使用常量的所有模塊。

如果您對內存分段感興趣並了解編譯器和鏈接器如何管理內存,請嘗試更改鏈接選項以生成映射文件。

[編輯] 但實際上,您可以輕松更改 const 結構中的 const 成員,前提是該常量位於可寫數據段中。 你可以試試這個:

int someFunc()
{
    const ST CONST_ONSTACK = { .a = 10, .b = 20 }; // the constant is on the stack...
    *(int*)&(CONST_ONSTACK.a) = 3}
    return CONST_ONSTACK.a;
}

如果您的編譯器很好,您應該收到警告。

這是另一種方法,您可以如何使調用方的結構只讀,並使其保持讀/寫以供內部使用:

例如,這是一個虛構的 HTTP 解析器:

typedef const struct ___http_message {
    struct {
        char* name;
        char* value;
    } *headers;
    char* body;
} http_message_t;

http_message_t* http_parse(char const* data) {
    struct ___http_message* msg = calloc(1, sizeof(struct ___http_message));
    msg->headers = calloc(3, sizeof(*msg->headers));
    msg->headers[0].name = strdup("Content-Type");
    msg->headers[0].value = strdup("application/json");
    msg->headers[1].name = strdup("Content-Length");
    msg->headers[1].value = strdup("20");
    msg->body = strdup("{ \"hello\": \"world\" }");
    return msg;
}

void http_free(http_message_t* message) {
    struct ___http_message* msg = (struct ___http_message*)message;
    free(msg->headers[0].name);
    free(msg->headers[0].value);
    free(msg->headers[1].name);
    free(msg->headers[1].value);
    free(msg->headers);
    free(msg->body);
    free(msg);
}

int main(int argc, char const *argv[]) {
    http_message_t* msg = http_parse("...");
    printf("%s: %s\n", msg->headers[0].name, msg->headers[0].value);
    printf("%s: %s\n", msg->headers[1].name, msg->headers[1].value);
    printf("%s\n", msg->body);

    msg->body = "123"; // cannot assign to variable 'msg' with const-qualified type 'http_message_t *' (aka 'const struct http_message_tag *')
}
// output
Content-Type: application/json
Content-Length: 20
{ "hello": "world" }

您的http_message_t*對於調用者來說始終是只讀的,因此處理起來更安全。

這種做法是合法的,而且不臭!

暫無
暫無

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

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