为什么 strcpy 不为 dest 使用 const 指针?
Why doesn't strcpy use a const pointer for dest?
为什么strcpy的签名是这样的:
char *strcpy(char *dest, const char *src);
而不是这个?
char *strcpy(char *const dest, const char *src);
据我所知,函数永远不会改变指针。
我是不是误解了 const 指针的用途?在我看来,当我编写的函数接受一个不会更改的指针(通过 realloc 等)时,我将其标记为 const 指针,这样调用者就可以确信他们的指针不会在它们上面移动。 (以防他们有其他 structs/etc。引用该指针位置会变得过时)
这是一个好的做法,还是会产生意想不到的后果?
strcpy
的源代码大致是这样的:
char *strcpy(char *dest, const char *src)
{
while (*dest++ = *src++);
}
这里我们实际上修改了 dest
但这对调用者没有影响,因为在 strcpy
函数内部, dest
是一个局部变量。
但以下代码无法编译,因为 dest
是常量:
char *strcpy(char * const dest, const char *src)
{
while (*dest++ = *src++);
}
我们需要这样写:
char *strcpy(char * const dest, const char *src)
{
char *temp = dest;
while (*temp++ = *src++);
}
引入了一个不必要的 temp
变量。
函数参数上的限定符在声明(原型)中完全被忽略。这是 C 语言所要求的,而且它是有道理的,因为这种限定可能对函数的调用者没有任何意义。
在const char *src
的情况下,参数src
不是合格的;它指向的类型是合格的。在您对 dest
的假设声明中,限定符适用于 dest
,因此没有意义。
As far as I know, the function will never change the pointer.
是的,但你可以。您可以自由更改指针。无需制作 dest
指针 const
。
例如:
int main(void)
{
char *s = "Hello";
char *d = malloc(6);
strcpy(d, s);
puts(d);
strcpy(d, "World");
puts(d);
}
按你说的标记为const是没有意义的。在 C 中,函数参数作为副本传递。意思是strcpy()
里面的变量dest
其实是一个新变量(压栈),里面的内容(这里是地址)是一样的
看这个函数原型:
void foo(int const a);
这没有语义值,因为我们知道我们传递给 foo()
的原始变量 a 不能更改,因为它是一个副本。只有副本可能会发生变化。当fooreturn时,我们保证原变量a
不变
在函数参数中,只有当函数实际上可以持续改变变量的状态时,您才希望使用关键字 const。例如:
size_t strlen(const char *s);
这将变量s
的内容(即存储在地址s
指向的值)标记为const。因此,你保证你的字符串在 strlen returns.
时不会改变。
char *foo(char *const dest, const char *src) { ... }
表示指针dest
在函数体中不会改变。
不代表dest
指向的数据会变或不会变
const char *src
确保调用代码 src
指向的数据不会改变。
在调用像 strcpy(d,s)
或 foo(d,s)
这样的函数时,调用代码不关心函数是否更改 它的 指针副本。所有调用代码关心的是 s
或 d
指向的数据是否被更改,这是由 *
[=22] 左侧的 const
控制的=]
char *dest, // data pointed by `dest` may or may not change.
const char *src // data pointed by `src` will not change change because of `src`.
为什么strcpy的签名是这样的:
char *strcpy(char *dest, const char *src);
而不是这个?
char *strcpy(char *const dest, const char *src);
据我所知,函数永远不会改变指针。
我是不是误解了 const 指针的用途?在我看来,当我编写的函数接受一个不会更改的指针(通过 realloc 等)时,我将其标记为 const 指针,这样调用者就可以确信他们的指针不会在它们上面移动。 (以防他们有其他 structs/etc。引用该指针位置会变得过时)
这是一个好的做法,还是会产生意想不到的后果?
strcpy
的源代码大致是这样的:
char *strcpy(char *dest, const char *src)
{
while (*dest++ = *src++);
}
这里我们实际上修改了 dest
但这对调用者没有影响,因为在 strcpy
函数内部, dest
是一个局部变量。
但以下代码无法编译,因为 dest
是常量:
char *strcpy(char * const dest, const char *src)
{
while (*dest++ = *src++);
}
我们需要这样写:
char *strcpy(char * const dest, const char *src)
{
char *temp = dest;
while (*temp++ = *src++);
}
引入了一个不必要的 temp
变量。
函数参数上的限定符在声明(原型)中完全被忽略。这是 C 语言所要求的,而且它是有道理的,因为这种限定可能对函数的调用者没有任何意义。
在const char *src
的情况下,参数src
不是合格的;它指向的类型是合格的。在您对 dest
的假设声明中,限定符适用于 dest
,因此没有意义。
As far as I know, the function will never change the pointer.
是的,但你可以。您可以自由更改指针。无需制作 dest
指针 const
。
例如:
int main(void)
{
char *s = "Hello";
char *d = malloc(6);
strcpy(d, s);
puts(d);
strcpy(d, "World");
puts(d);
}
按你说的标记为const是没有意义的。在 C 中,函数参数作为副本传递。意思是strcpy()
里面的变量dest
其实是一个新变量(压栈),里面的内容(这里是地址)是一样的
看这个函数原型:
void foo(int const a);
这没有语义值,因为我们知道我们传递给 foo()
的原始变量 a 不能更改,因为它是一个副本。只有副本可能会发生变化。当fooreturn时,我们保证原变量a
不变
在函数参数中,只有当函数实际上可以持续改变变量的状态时,您才希望使用关键字 const。例如:
size_t strlen(const char *s);
这将变量s
的内容(即存储在地址s
指向的值)标记为const。因此,你保证你的字符串在 strlen returns.
char *foo(char *const dest, const char *src) { ... }
表示指针dest
在函数体中不会改变。
不代表dest
指向的数据会变或不会变
const char *src
确保调用代码 src
指向的数据不会改变。
在调用像 strcpy(d,s)
或 foo(d,s)
这样的函数时,调用代码不关心函数是否更改 它的 指针副本。所有调用代码关心的是 s
或 d
指向的数据是否被更改,这是由 *
[=22] 左侧的 const
控制的=]
char *dest, // data pointed by `dest` may or may not change.
const char *src // data pointed by `src` will not change change because of `src`.