我们可以为char *分配内存,但将其作为const char *返回吗?

huangapple go评论83阅读模式
英文:

Can we allocate memory for char * but return it as const char *?

问题

In the provided code example, returning a non-const char * as const char * is well-defined and serves the purpose of preventing the caller from modifying the content of the buffer without a type cast. This code does not invoke undefined behavior, and it is a common practice to use such a pattern to ensure the immutability of the data pointed to by str.

英文:

Is it correct to return const char * from a function when the actual buffer being returned is not a constant array?

For example, in this minimal example below, buffer is a non-const char * but then it is returned as const char *.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char *str_alloc(const char *str, size_t n)
{
    char *buffer;
    if ((buffer = malloc(n)) != NULL) {
        memcpy(buffer, str, n);
    }
    return buffer;
}

int main()
{
    const char *str = str_alloc("hello", 6);

    if (str == NULL) {
        fprintf(stderr, "memory allocation error\n");
        return EXIT_FAILURE;
    }

    printf("str: %s\n", str);

    // str[0] = 'H'; // error: read-only variable is not assignable

    free((void *) str);

    return 0;
}

In the above example, returning a non-const char *buffer as const char * helps me to enforce that the caller cannot modify the content of the buffer without an explicit type cast. But I would like to know if this is well-defined code or if this code invokes undefined behaviour due to treating char * as const char *?

答案1

得分: 4

这是一个良好定义的代码,因为你限制了值的使用可能性。俗话说:“能做多的人,能做少的事情。”相反的情况则不成立,需要显式转换。

但是你的代码存在问题。将字符串的大小作为参数传递是不安全的。在你的示例中,你不会在分配的缓冲区中复制'\0'。因此,字符串没有被正确终止。你的程序行为未定义,可能会导致段错误,因为printf会尝试访问缓冲区末尾之外的数据。

最好的做法是在str_alloc函数中确定字符串的长度。

英文:

This is well defined code since you restrict the usage possibility of the value. As the saying goes "who can do more, can do less". The opposit would not be valid and would require an explicit cast.

But there is a problem with your code. Passing the size of the string as argument is unsafe. In your example, you won’t copy the '\0' in the allocated buffer. As a consequence, the string is not properly terminated. The behavior of your program is undefined and could end in a segmentation fault because the printf would try to access data beyond the end of the buffer.

It would be preferable that the length of the string is determined in the str_alloc function.

答案2

得分: 1

是的,这是明确定义的。

支持这一点是C语言允许你自由地将指向更不限定类型的指针转换为指向更限定类型的指针。

但是,将指针转换回更不限定类型的指针(在这种情况下,从char const*char *)也是可能的,但需要显式转换,因为结果指向更不限定类型的指针(在这种情况下,char *)只能用于已定义的解引用,前提是目标的有效类型不比指针目标更限定(参考6.5p7)。

在您的情况下,char const*的用户可以将其强制转换回char *然后进行解引用,因为内存实际上是非const的,但如果您返回了一个char const*指针,例如,来源于static char const x[] = "foo";,那么将其强制转换为char *并进行解引用将导致未定义的行为,因为目标的有效类型比char更限定。

英文:

Yes, that's well defined.

Supporting this is why C lets you freely convert pointers to less qualified types to pointers to more qualified types.

Converting back to a pointer to a less qualified type (in this case char const* => char *) is also possible, but requires an explicit cast, because the resulting pointer to a less qualified type (in this case char *) may only be used for defined dereferencing iff the effective type of the target isn't more qualified than the pointer target (6.5p7).

In your case, the user of the char const* may cast it back to char * and then dereference, because the memory is effectively non-const, but if you returned a char const* pointer derived from e.g., a static char const x[] = "foo";, then casting to char * and dereferencing would lead to undefined behavior, because the target's effective type is more qualified than char.

huangapple
  • 本文由 发表于 2020年1月6日 17:11:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/59609338.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定