【问题标题】:Why strcpy takes const char* for src instead of char *?为什么 strcpy 将 const char* 用于 src 而不是 char *?
【发布时间】:2021-07-18 19:53:00
【问题描述】:

我实现了自己的 strcpys 来查找 src 与 const char* 和 char * 之间是否有任何区别,但没有发现以下 2 之间有任何区别,两者的工作方式相同。

char * my_strcpy(char*dest, char* src)
{
    while ('\0' != *src)
        *dest++ = *src++;
    *dest++ = '\0';
        return dest;
}

char * my_strcpy2(char*dest, const char* src)
{
    while ('\0' != *src)
        *dest++ = *src++;
    *dest++ = '\0';
    return dest;
}

strcpy 是否有任何理由将源指针作为 const char* 而不是 char*?

【问题讨论】:

  • 它没有。 strcpy 接受 const char *src
  • 恕我直言,出于历史原因。在大多数情况下, strcpy() 可以内联,因此无论如何差异都是徒劳的。
  • 实际上 strcpy 自 C99 标准以来,其源参数定义为 const char *restrict。参见例如this reference 了解有关 restrict 关键字的更多信息。
  • 谷歌“常量正确性”。
  • 顺便说一句,你的函数的返回值很奇怪。

标签: c pointers


【解决方案1】:

对于初学者函数strcpy 返回指向目标字符串的指针。您的函数还应该返回指向目标字符串的指针。这是 C 标准中处理字符串的函数的通用约定。

所以函数可以如下所示

char * my_strcpy( char *dest,  const char *src )
{
    char *p = dest;

    while ( *p++ = *src++ );

    return dest;
}

在这种情况下,例如可以通过以下方式调用它

const char *hello = "Hello, World!";
char s[14];

puts( s, hello );

将函数的第二个参数指定为指向常量字符串的指针意味着 1) 函数保证它不会更改指向的字符串,并且 2) 允许传递给函数常量字符串。

指向非常量对象的指针可以隐式转换为指向常量对象的指针。如果没有显式强制转换,则不允许反向操作。

因此,如果将参数声明为指向常量字符串的指针,那么您可以将非常量字符串与常量字符串一起传递给与参数相同的函数。否则无法使用常量字符串调用该函数,因为编译器将发出一个错误,指出它无法将 const char * 类型的对象转换为 char * 类型的对象。

【讨论】:

  • @BLUEPIXY 谢谢。由于复制和粘贴,这是一个错字。
【解决方案2】:

“没有发现以下 2 之间有任何区别”——在您最疯狂的梦想中,这些区别可能是什么?

const 声明的唯一区别是 在调用方。 通过 const 参数声明,函数承诺不会更改通过指针访问的内存。它承诺只通读它,这与strcpy() 的语义一致。 (注:函数是否真的不通过指针写根本无法保证,但它承诺。)

因此,调用者可以使用指向常量数据的指针调用函数,并假设函数不会尝试写入它。

这在句法、逻辑和实质上都很重要:

  • 该语言允许调用者提供指向 const 数据的指针作为参数(对于您的第一个非 const 版本,它不允许这样做)。
  • 调用者可以确保敏感数据不会在函数内部被更改作为副作用;在这里想象一个指向内核数据结构的指针。 (反例:strtok() 写入原始字符串,因此未声明为 const!)
  • 数据可能是物理只读的(例如,它可能被烧录到控制器的 ROM 中),因此尝试写入它会导致引用出色的 Max Barry:a "catastrophic system failure. (...) I'm not saying it's a big deal."

【讨论】:

  • 实际上不通过指针写入根本不保证...是的,但是如果程序员不做坏事(强制删除常量),编译器会抱怨。
  • @Jean-BaptisteYunès 没错,实现必须使用演员表或做一些更虚假的事情。
【解决方案3】:

strcpy 是否有任何理由将源指针作为 char* 而不是 const char*?

源指针应该是const char *。原因对于所有不打算在函数内部意外更改源的函数(不仅仅是strcpy)都很常见。

这种做法适用于strcpy 等库函数或您自己的自定义函数。与 strcpy 之类的库函数一样,源不可能意外更改。但是对于您自己(或其他所有人)的自定义函数,任何事情都可能发生。如果你确实修改了它不小心,那么你会得到一个编译错误告诉你。这就是const 发挥作用的时候。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-14
    相关资源
    最近更新 更多