考虑以下代码:
struct ns_test{
char *str;
};
struct ns_test *ns_test_alloc(char *str){
struct ns_test *nt = malloc(sizeof(*nt));
nt->str = str;
return nt;
}
const char *ns_test_get_str(struct ns_test *tst){
return tst->str;
}
void ns_test_release(struct ns_test* tst){
free(tst);
}
void ns_test_set_char(struct ns_test *tst, size_t i, char c){
tst->str[i] = c;
}
int main(void){
char arr[] = "1234567890";
struct ns_test *ns_test_ptr = ns_test_alloc(arr);
const char *str = ns_test_get_str(ns_test_ptr);
printf("%s\n", str); //1234567890
ns_test_set_char(ns_test_ptr, 4, 'a');
printf("%s\n", str); //1234a67890
}
问题是 :代码的行为是否未定义?
我认为是。
该标准在6.7.3(p6)
中指定:
如果试图修改用 通过使用带有非const限定的左值的const限定类型 类型,行为是不确定的。
因此,要避免此类UB,我们需要const char *ns_test_get_str(struct ns_test *tst)
复制char *str
。但主要要点是避免复制,并将修改内容限制为唯一的void ns_test_set_char(struct ns_test *tst, size_t i, char c)
,它可能会进行健全性检查或其他先验。
答案 0 :(得分:2)
此处的键是“使用const限定类型定义的对象”。重要的是如何定义(IOW,“为其分配内存”)所指向的对象。如果未“创建” const
作为“对象”,则使用多少个const或非const指针和引用都没有关系-您仍然可以对其进行修改。
所以
const int i = 0;
int *p = (int*)&i;
*p = 1;
是UB。
而
int i = 0;
const int *cp = &i;
int *p = (int*) cp;
*p = 1;
很好。
我怀疑这甚至可以与new
一起使用:
const int *cp = new const int(0);
int *p = (int*) cp;
*p = 1;
从技术上讲是UB。
它确实在cpp.sh上编译时没有警告,但这并不意味着什么。
更新:正如Christian Gibbons所指出的,问题中的语言是C,因此new
运算符部分不适用。 malloc()
和朋友永远不会const
。
稍微扩展一下-用这种方式编写标准的一个可能原因是,使编译器可以自由使用const值的只读存储器。在这种情况下,写入这些位置将导致崩溃或死机。换句话说,UB。