修改由const char数组引用的非const char数组

时间:2019-05-08 18:17:59

标签: c const

考虑以下代码:

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),它可能会进行健全性检查或其他先验。

1 个答案:

答案 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。