如果`uintptr_t`可以用来存储指针和数字,为什么`void*`不能做同样的事情?

Swift 或 Rust 等语言中的枚举支持一种混合的“选择数据”机制,这样我就可以定义如下类型:

enum SomeOption {
  None,
  Index(int),
  Key(string),
  Callback(fn),
}
enum SomeOption {
  None,
  Index(int),
  Key(string),
  Callback(fn),
}

现在,如果我是用C实现这一点,我的理解是,这样的事情就不会是有效的:

我不确定这样做到底有什么风险,但是根据例如可以指针存储值以及空指针的用途是什么?我应该存储在 avoid*中的唯一内容是实际地址和NULL. [旁白:请对在 a中存储回调函数指针的单独问题视而不见void*,我在编写此示例时忘记了这个问题。]

我想更合适的方法是使用联合,例如:

typedef struct {
   my_choice value_type;
   union {
      int number_value;
      char* string_value;
      void* pointer_value;
   };
} my_option;

……无论如何,这可能更好。我特别想知道void* valueversion的无效性。如果我是(而不是union解决)简单地替代uintptr_t的地方void*

typedef struct {
   my_choice value_type;
   uintptr_t value;
} my_option;

将存储一个指针指向一个串/回调/空在内的多个uintptr_t value这种结构的字段是有效的,并[至少POSIX-]便携式码?如果是这样,为什么可以,但不是看似等效的void* value版本?

回答

问题是我不明白规则是否不同。我可以用 a uintptr_t/ intptr_tvs. a做什么void*,如果是这样,为什么它们会不同?

规则是不同的,因为它们处于边缘,处于机器实际可以做什么、人们想要做什么以及语言标准说他们可以做什么之间的边界(或灰色区域)内。

现在,是的,在“传统”架构上,指针和整数都只是某种大小的二进制整数,因此很明显可以在两者之间进行混合匹配。

而且,再次是的,这显然是一些人发现自己想做的事情。你有一个庞大的、异构的数组,其中一些是普通数字,一些是数据指针,也许其中一些是函数指针,你有办法知道哪个是哪个,有时将它们存储在一个大型异构数组中确实看起来很整洁。或者你有一个函数,它的参数有时想是一个整数,有时想成为一个指针,你也可以接受。(嗯,除了你从编译器那里得到的所有警告,以及来自语言律师和 SO 常客的讲座。)

但是还有 C 标准,它在区分整数、数据指针和函数指针方面有些困难。在某些架构中,这些确实不能互换,并且尝试是个坏主意。而 C 标准一直试图适应这些架构。(如果你不相信我,问,因为例子确实存在。)

C 标准可以说所有指针和所有整数都可以更自由地互换。听起来这就是 Swift 和 Rust 所做的。但听起来 Swift 和 Rust 也无法在那些假设的“异国情调”架构上实现。

These discussions get tricky because they're also at the intersection between language standards and programming practices. If you know you're always going to be using machines where integers and pointers are interchangeable, if you don't care about portability to the other, "exotic" architectures, you could just say so, and ignore the warnings, and move on -- unless your house style guide says that casts are forbidden, or your software development plan says that your code must be strictly conforming and compile without warnings. Then you might find yourself arguing with, or trying to change, the C Standard, just to get around your own SDP. (My advice: make sure that your style guide and your SDP have waiver mechanisms.)

Some day the C standard will probably get less "protective" (enabling?) of those exotic architectures. For example, I've heard it's been debated to drop the accommodation of one's complement and sign/magnitude machines, and to build the definition of two's complement into the next revision of the C Standard. But if that happens, or if other guarantees/accommodations change, it won't mean that C compilers and C programs for the exotic machines can't be written any more -- it will just mean that programmers for those machines will have to apply their own rules (like, "don't assign between int and void * and void (*)()") that aren't actually in the standard any more. (Or, equivalently, it means that strictly conforming code written for "normal" architectures won't automatically be portable to the exotic ones. Also, I guess, that the vendors of compilers for the exotic architectures won't be able to claim standards compliance any more.)


以上是如果`uintptr_t`可以用来存储指针和数字,为什么`void*`不能做同样的事情?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>