正如其他人所说,这在 C 中是不可能的。你是正确的,它int
是三种类型中最大的,但你似乎忽略了这个事实的含义。
为什么这在 C 中是不可能的?
在 C 中,数据直接存储在内存中,没有元数据开销。变量直接映射到内存中的数据。除非您创建它(违反您的要求,即没有标志或跟踪正在传递的指针类型),否则没有与变量一起存储的信息,例如:
- 它是什么类型
- 变量是否已初始化
- 变量是否在范围内
- 或(对于数组/字符串)使用的长度或可用大小
就像其他语言一样。相反,这个信息应该由程序员维护,要么通过创建一个struct
来存储这些信息,要么让程序员记住发生了什么。
C 是一种系统编程语言,它适用于系统编程的部分原因是它不像 Java 或 C# 那样具有这种开销。
好的,但为什么它在工会中不起作用?
所指向的类型的各种大小的含义是什么?考虑以下内存图,其中每个字符为 4 位,int 为 32 位,short 为 16 位,char 为 8 位:
半字节:89ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
[other ][data ][int ][int ][int ][mo][re][ ][da][ta] // 整数
[other ][data ][sh][or][t ][sh][or][t ][mo][re][ ][da][ta] // 短裤
[其他][数据][][][][][][][][][][][][][mo][re][][da][ta] // 字符
请注意,这完全忽略了对齐和字节顺序问题;有一些平台(包括 ARM,我在您的其他一些问题中看到)对对齐做出了某些保证,可以帮助您。(†)
但是,对于静态内存或堆上的内存,问题仍然存在。考虑如果将字符串存储ABCDEFGHIJKL
在字符数组中会发生什么。记住 ASCIIA
是 0x41,这将在内存中变为以下内容:
[其他][数据]4142434445464748494A4B4C[mo][re][][da][ta]
现在假设您传递了一个指向C
函数的指针,该函数将 this 取消引用为整数:
[int] // 指向 C 的 Int 指针
[其他][数据][][][][][][][][][][][][][mo][re][][da][ta] // 字符
[其他][数据]4142434445464748494A4B4C[mo][re][][da][ta]
^-- C 在这里;0x43
在此处使用 int 指针将违反 C 规范。
如果这还不够,并且我们假设您的编译器在逻辑上运行,它将尝试跨字边界取消引用内存,这可能会引发总线错误或使用错误(我忘记了它在 ARMv7 上的实际作用,但其中任何一个错误都会终止您的程序)。
如果这仍然不够,并且它以某种方式完成了所要求的操作,则该操作将产生错误的答案,因为您正在使用值 0x43444546 而不是 0x43。
关于 ARM 处理器上的内存对齐的一些脚注
(†) 例如,在 ARM 上,ABI 指定堆栈在正常使用中必须是字对齐的 ( sp % 4 == 0
),在这种情况下,您的代码可能会工作,如下图所示:
0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF
[其他][数据][int][int][int][mo][re][][da][ta]
[其他][数据][sh] [or] [t] [sh] [or] [t] [mo] [re] ...
[其他][数据][][][][][][][][]...
堆栈还保证对公共接口是双字对齐的,并且在内部不必维护它,有关详细信息,请参见 AAPCS 中的 5.2.1。尽管如此,这不是您想要依赖的东西(在大多数情况下可移植代码更可取),或者甚至需要知道,除非您正在编写编译器或原始汇编代码