【问题标题】:Does C's void* serve any purpose other than making code more idiomatic?除了使代码更惯用之外,C 的 void* 是否还有其他用途?
【发布时间】:2018-01-06 00:20:25
【问题描述】:

C 的void* 是否以编译器优化等形式提供了一些好处,或者它只是char* 的惯用等价物? IE。如果 C 标准库中的每一个 void* 都被 char* 替换,除了代码的易读性之外会不会有任何损坏?

【问题讨论】:

  • void* 用于未知类型,如果您正在获取输入或通过不同类型的随机列表进行排序,则可以使用。
  • 您说您希望您的语言“没有任何类型别名”,但您打算将任意指针投射到uint8*
  • void * 对于像 memcpymalloc 这样的函数很有用,这些函数处理内存而不关心内存中存储的内容。
  • malloc 的类型签名在您的语言中会是什么样子? (你的语言支持泛型/模板吗?)
  • void* 是后来引入 C 语言的 generic 指针类型。事实上,K&R C确实为此目的使用了char*。主要缺点是你不能声明一个真正接受字符指针而不是其他任何东西的函数,因为它已经用于任何通用函数。例如。 strcmp 可能会占用原始存储空间。

标签: c void-pointers


【解决方案1】:

在最初的 K&R C 中没有 void * 类型,char * 被用作泛型指针。

void * 有两个主要用途:

  1. 当指针被用作通用指针时,它会很清楚。以前,您无法判断 char * 是用作指向实际字符缓冲区的指针还是用作通用指针。

  2. 它允许编译器在您尝试取消引用或对泛型指针执行算术运算时捕获错误,而不是先将其转换为适当的类型。不允许对 void * 值进行这些操作。不幸的是,一些编译器(例如gcc)默认允许对void * 指针进行算术运算,因此它并不安全。

【讨论】:

  • 请注意,GCC 有一个扩展(默认启用),它允许在 void * 上进行算术运算,表现得就像是 char *。考虑到标准的要求 (C11 §6.2.5 ¶28),这并非完全不合理:指向 void 的指针应具有与指向字符类型的指针相同的表示和对齐要求。 但它确实破坏了保护你提到了。
  • @JonathanLeffler 因此是“允许”而不是“强制”。
  • @JonathanLeffler 是否允许取消引用它们?如果您尝试使用结果而不进行强制转换,它仍然会捕获它。
  • 我认为即使在 GCC 中也不能取消引用 void *。一方面,GCC 中的偏差大多是合理的——它在计算偏移量之前节省了一些转换为char *——但它确实违反了标准并且让新手措手不及。 (GCC 的人可能会说他们不迎合新手,也不关心其他编译器的可移植性。-pedantic 抓住了滥用。但它确实需要-pedantic;否则,允许不加注释。)
  • @SamClaus 您不需要允许隐式转换。 C++ 没有。
【解决方案2】:

在后来引入void * 之前,C 使用char * 作为通用指针类型多年来相处得很好。所以这显然不是绝对必要的。但是编程语言是一种交流——不仅仅是告诉编译器要做什么,而是告诉其他阅读程序的人要做什么。任何使语言更具表现力的东西都是一件好事。

【讨论】:

  • 谢谢。这就是为什么我说我的语言已经命名参数[用于函数调用]。因此,与其为函数提供可能会混淆任何阅读代码的人的未命名char*,不如将​​参数命名为rawptr,因此调用函数的代码仍然很清晰,无需void*
  • @SamClaus:您声称命名函数参数不需要 void* 类型,但 C 也有命名函数参数,并使用 void* 类型(有充分的理由)。
  • @MarkBenningfield 好吧,首先我编辑了我的问题以简化它并删除我的语言设计的上下文,以使我试图弄清楚的内容尽可能清晰,但是既然你带来了向上:我的意思是当你调用你命名参数的函数时,采用原始指针的参数名称应该适当命名,所以在使用函数的任何地方都很明显指针将被使用为了。而且我相信像myFunc(myStructPtr) 这样对函数myFunc(void* ptr) 的调用将隐式转换为void*,这意味着void* 甚至没有帮助易读性。
  • @SamClaus:使用 void* 的全部意义在于解决歧义。如果您说没有必要,因为可以依赖开发人员使用正确且有意义的参数名称,那么恐怕您过于乐观了。
  • @MarkBenningfield 你是对的——我知道我对很多错误的参数名称感到内疚——但我必须权衡利弊,因为void* 仅在某些情况下惯用地有用开发人员应该知道他们在 C 中做了什么(并且 GCC 允许像 char* 一样对其进行算术运算),我宁愿将其排除在外并使用更少的原语。
【解决方案3】:

C 的 void* 除了使代码更惯用之外,还有其他用途吗?

如果 C 标准库中的每一个 void* 都被 char* 替换,除了代码的易读性之外是否会损坏任何东西?

C11 介绍了_Genric。因此,_Generic(some_C_standard_library_function()) ... 代码的编译方式可能完全不同,具体取决于返回类型是否为 void *char *int * 等。

【讨论】:

    猜你喜欢
    • 2018-05-04
    • 1970-01-01
    • 2019-10-14
    • 2010-10-25
    • 2014-04-25
    • 2020-02-27
    • 1970-01-01
    • 2015-12-08
    • 2023-02-09
    相关资源
    最近更新 更多