[英]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.