特殊体系结构的C指针算法

特殊体系结构的C指针算法,c,pointers,language-lawyer,pointer-arithmetic,C,Pointers,Language Lawyer,Pointer Arithmetic,我试图更好地理解C标准。我特别感兴趣的是指针算法如何在一个不寻常的机器体系结构的实现中工作 假设我有一个带有64位宽寄存器的处理器,它连接到RAM,每个地址对应一个4位宽的单元。此机器的C实现将CHAR_位定义为等于8。假设我编译并执行以下代码行: char *pointer = 0; pointer = pointer + 1; 执行后,指针等于1。这给人的印象是,一般情况下,char类型的数据对应于机器上最小的可寻址内存单元 现在假设我有一个12位宽寄存器的处理器,它连接到RAM,每个地址

我试图更好地理解C标准。我特别感兴趣的是指针算法如何在一个不寻常的机器体系结构的实现中工作

假设我有一个带有64位宽寄存器的处理器,它连接到RAM,每个地址对应一个4位宽的单元。此机器的C实现将CHAR_位定义为等于8。假设我编译并执行以下代码行:

char *pointer = 0;
pointer = pointer + 1;
执行后,指针等于1。这给人的印象是,一般情况下,char类型的数据对应于机器上最小的可寻址内存单元

现在假设我有一个12位宽寄存器的处理器,它连接到RAM,每个地址对应一个4位宽的单元。此机器的C实现将字符位定义为等于12。假设为这台机器编译和执行了相同的代码行。指针是否等于3


更一般地说,当您递增指向字符的指针时,地址是否等于字符位除以计算机上存储单元的宽度?

指针递增的最小值是它们“指向”的数据类型的宽度,但不能保证精确递增到该大小

出于内存对齐的目的,很多时候,指针可能会增加到下一个内存字对齐,超过最小宽度

所以,一般来说,您不能假定这个指针等于3。它很可能是3、4或更大的数字

这里有一个例子

struct char_three {
   char a;
   char b;
   char c;
};

struct char_three* my_pointer = 0;
my_pointer++;

/* I'd be shocked if my_pointer was now 3 */
内存对齐是特定于机器的。除了大多数机器将一个字定义为第一个地址,该地址可以与总线上的内存提取对齐外,我们无法对此进行概括。有些机器可以指定与总线回迁不一致的地址。在这种情况下,选择跨越对齐的两个字节可能会导致加载两个字

大多数系统不会毫无怨言地接受非对齐边界上的单词加载。这意味着,如果需要最大密度,则应用一点锅炉板组件来将提取转换到继续的单词边界

大多数编译器更喜欢速度而不是数据的最大密度,因此它们会对齐结构化数据以利用字边界,从而避免额外的计算。这意味着在许多情况下,未仔细对齐的数据可能包含未使用的字节“孔”

如果您对上述摘要的细节感兴趣,您可以阅读其中讨论对齐(以及由此产生的)填充的内容

指针是否等于3

这个标准没有说明指针是如何实现的。该标准说明了以特定方式使用指针时会发生什么,而不是指针的值

我们所知道的是,将1添加到一个char指针上,将使指针指向下一个char对象——无论它在哪里。但指针的价值却与此无关

所以当你这么说的时候

pointer = pointer + 1;
将使指针等于1,这是错误的。《标准》对此没有任何规定

在大多数系统上,
char
是8位的,指针是引用8位可寻址内存位置的(虚拟)内存地址。在这样的系统上,增加一个字符指针将使指针值(又称内存地址)增加1。然而,在不寻常的体系结构上,没有办法判断

但是,如果您有一个系统,其中每个内存地址引用4位,一个字符是12位,那么很可能
++pointer
会将指针增加3位

char*指针=0
执行后,指针等于1

不一定。 由于
0
是一个空指针常量,因此此特殊情况为空指针。严格地说,这样的指针不应该指向有效的对象。如果查看指针中存储的实际地址,它可能是任何内容

撇开空指针不谈,C语言希望您通过首先指向数组来进行指针运算。或者在
char
的情况下,您还可以指向一块通用数据,例如结构。其他一切,比如你的例子,都是未定义的行为

此机器的C实现将字符位定义为等于12

C标准将
char
定义为等于一个字节,因此您的示例有点奇怪和矛盾。指针算法将始终增加指向数组中下一个对象的指针。该标准实际上根本没有提到地址的表示,而是您虚构的示例,它会将地址合理地增加12位,因为这是
字符的大小


即使从学习的角度来看,虚构的计算机也毫无意义。我建议把重点放在现实世界的计算机上。

这个问题的困惑似乎是因为C标准中的“byte”一词没有典型的定义(即8位)。具体而言,C标准中的单词“byte”表示位的集合,其中位的数量由实现定义的常量
CHAR\u bits
指定。此外,C标准定义的“字节”是C程序可以访问的最小可寻址对象

这就留下了一个悬而未决的问题,即“可寻址”的C定义与“可寻址”的硬件定义之间是否存在一对一的对应关系。换句话说,硬件是否可能寻址小于“字节”的对象?如果(在OP中)一个“字节”占用3个地址,那么这意味着“字节”访问具有对齐限制。也就是说,3和6是有效的“字节”地址,但4和5不是。第6.2.8节讨论了物体的对齐,禁止这种情况

这意味着
char a[10];
char *p = a;
p++;
#include <assert.h>
int main(void)
{
    T x[2]; // for any object type T whatsoever
    assert(&x[1] - &x[0] == 1); // must be true
}
#include <assert.h>
int main(void)
{
    T x[2]; // again for any object type T whatsoever
    char *p = (char *)&x[0];
    char *q = (char *)&x[1];
    assert(q - p == sizeof(T)); // must be true
}
#include <assert.h>
#include <inttypes.h>
int main(void);
{
    T x[2];
    uintptr_t p = (uintptr_t)&x[0];
    uintptr_t q = (uintptr_t)&x[1];
    assert(q - p == sizeof(T)); // implementation-defined whether true
}