我必须在C中更改const结构实例的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
}
但是,如果实例是常量,我没有成功尝试更改struct实例的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"最后一个场景中的成员价值? 如果没有,为什么?
答案 0 :(得分:10)
我已经知道可以按如下方式更改const基本类型:
const int a = 2; *(int*)&a = 3;
您的编译器允许您这样做的事实并不合法。此代码调用未定义的行为,因此如果您在其他平台上运行该程序或使用其他编译器,则同一程序可能会失败或崩溃。
*(int *)(&((*(ST*)(&st)).a)) = 5; //works fine , no problem
此代码具有相同的问题:它调用未定义的行为。
您尝试的最后一段代码(您猜对了!)未定义的行为。但是,这次程序崩溃而不是运行完成。
答案 1 :(得分:1)
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;
}
如果您的编译器有任何好处,您应该收到警告。
答案 2 :(得分:0)
这是另一种方法,如何使结构体对调用者只读,并使其保持读/写以供内部使用:
例如这里是一个虚构的 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*
对调用方始终是只读的,因此处理起来更安全。
这种做法是合法的,而且不臭!