【问题标题】:How to deal with C/C++ ambiguity of pointers?如何处理指针的 C/C++ 歧义?
【发布时间】:2021-10-17 01:45:51
【问题描述】:

假设我们有一个简单的函数定义...

    void fun(type* var);

我怎么知道在函数中放什么......

  • 传递一个指向类型变量的指针,假设函数需要 仅指向一个元素的指针...
    type ch = ...;
    fun(&ch);
  • 传递类型数组,假设函数需要多种类型...
    type chArr[] = {...};
    fun(chArr);

我知道,我知道数组保存第一个元素的地址,因此您始终可以为每个指针创建一个包含一个值的类型数组,并且代码将是相同的。但是我怎么知道它需要 1 还是 >1 值???

当我们必须通过char* 时情况会变得更糟,因为我们无法知道函数是否需要\0 空终止符才能退出操作...

  • 传递一个指向 char 变量的指针,假设函数需要唯一指向一个 char 元素的指针...
    char ch = 'A';
    fun(&ch);
  • 传递 char 数组,假设函数需要许多 char 元素,末尾带有一个空指针...
    type chArr[] = "ABC";
    fun(chArr);

我知道,您通常从文档中知道要在代码中添加什么,但仍然...您是怎么知道的???

【问题讨论】:

  • "我知道数组保存第一个元素的地址" - 更准确地说,在某些情况下,传递数组会衰减变成指向第一个元素的指针。
  • 您的问题到底是什么?阅读文档已经是正确的方法。仅查看函数签名,您无法分辨出许多事情。那么你的观点是什么?如果您询问 C,请不要标记 C++。它们是不同的语言。
  • @JaMiT 我将其编辑为不是咆哮。
  • @UrošJarc 更好,但最后一行对于非咆哮者来说仍然很奇怪:​​“我知道,您通常从文档中知道要在代码中添加什么,但仍然......你怎么知道???” “你怎么知道?”的答案就在前面的陈述中:“您通常从文档中知道”。休息一下,从头开始重新写这个问题可能是一个好主意,在你从你的想法中清除掉你的胡言乱语之后。

标签: arrays c pointers


【解决方案1】:

我应该如何知道在函数中放入什么......

但是我怎么知道它需要 1 还是 >1 值???

仅查看函数的声明,您无法确定(除非声明用SAL annotations 修饰,而您的示例不是)。正如您所说,该函数可能需要指向单个对象的指针,或指向对象数组的指针。因此,要确定预期的行为,您必须查看函数的文档,或者如果您有权访问函数的实现代码,则必须查看它。

【讨论】:

  • 是的,你可能是对的,从注释中你可以假设很多事情,你能详细说明那个 SAL 注释吗?
  • 哦,我知道这是a header for only annotations COOL,我现在感觉好多了。
  • Linux 上的 gcc/clang 注释是否有任何标准或一些文档可以读取 gcc/clang 正在使用的所有注释列表?
  • 我们应该建议首先查看文档,而不是实现。 (很少有实现而不是文档,反之亦然。)文档是函数应该做什么的官方表达,而不是实现。实现的行为可能是文档指定行为的严格超集,因此从实现中推断出的行为可能无法承受未来版本的更改、移植到其他平台以及其他实现的更改。
【解决方案2】:

首先,你应该尝试根据函数参数是否声明为来决定

type *arg

type arg[]

type arg[] 形式表明该指针可能指向多个对象的数组。但是许多程序员拒绝这种形式(正是因为它可能会让人很困惑)并一直使用type *arg 形式。

一般规则:

  1. 如果它是一个char * 指针,它很有可能指向一个以空值结尾的字符串。
  2. 如果隔壁有 int nitemssize_t arrsize 参数,则指针可能指向给定大小的元素数组。
  3. 否则,如果有一个没有伴随“大小”参数的指针参数,它可能指向单个项目。 (标准示例为ctimestat。)

但是函数的文档应该总是说。

【讨论】:

  • 当然,如果有另一个参数可以传达元素计数,那么通常可以安全地假设该函数可能适用于数组的许多元素。但是,对不接受此类参数的函数进行其他假设是绝对不安全的。许多字符串函数可以作为现成的反例。
  • @JohnBollinger 好点,谢谢。答案已更新。
  • 是的,当有一个类似的参数名称并在末尾有 countsize 字样时,我可以看到它可能是数组,但通常我没有这样的奢侈。
【解决方案3】:

我应该如何知道在函数中放入什么......

Pass a pointer to a type variable, assuming that function needs only pointer to one element...

[...]

Pass type array, assuming that function needs many types...

首先,从被调用者的角度来看,它们之间没有本质区别。观察,例如...

    type chArr[1] = {...};
    fun(chArr);

。也就是说,指向标量的指针可以被视为指向单元素数组的第一个元素的指针(根据语言规范明确表示)。

我知道,我知道数组保存第一个元素的地址,所以你 总是可以为每个指针创建一个类型数组,其中包含一个值, 并且代码将是相同的。但是我怎么知道它想要 1 还是 >1 价值观???

你怎么知道 any 函数做了什么,或者它期望它的参数是什么,不管它们的类型是什么?一般来说,我们依赖文档,即使是我们自己编写的函数。 (你确实清楚而仔细地记录了你的代码,对吧?以后你会感谢你的。)

当我们必须传递 char 时,情况会变得更糟,因为我们无法知道函数是否需要 \0 空终止符才能退出操作...*

不,没有更糟。您没有特别的理由先验假设接受某种其他类型的数组的函数不依赖于它的结尾被标记值标记。

我知道,您通常从文档中知道要放入什么 代码但仍然...你怎么知道的???

您可以尝试根据函数名称、参数名称和类型以及函数的返回类型进行猜测,但这只是给您一个假设。也许是一个很好的假设,但您无法通过这种方式获得任何确定的信息。

如果您没有文档,或者它不完整,或者您不信任它,那么最终的办法就是查看代码。最好是源代码,但反汇编的目标代码也可以工作,如果你不顾一切的话。但是,如果您没有可以依赖的文档,那么您应该强烈考虑将函数丢弃的选项,或者至少避免直接使用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-11-13
    • 1970-01-01
    • 2010-10-25
    • 2010-10-04
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    相关资源
    最近更新 更多