Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/65.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C标准是否指定递增指针时进位传播的距离?_C_Pointers_Language Lawyer - Fatal编程技术网

C标准是否指定递增指针时进位传播的距离?

C标准是否指定递增指针时进位传播的距离?,c,pointers,language-lawyer,C,Pointers,Language Lawyer,考虑以下情况: 具有指针,当您不断递增这些指针时,这些指针将从0x0FFF滚动到0x0000,因为递增电路不会将进位传播到较高字节的较低Nyble。因此,例如,如果我想执行while(*ptr++)来遍历以null结尾的字符串,那么我可能会得到ptr指向数组外部的结果 在上,因为一个机器字比一个地址长,指针可能在包含地址的字的上半部分有标签和其他数据。在这种情况下,如果递增指针会导致溢出,则其他数据可能会被更改。同样的道理也适用于早期的Macintosh,在ROM还没有32位干净之前 所以我

考虑以下情况:

  • 具有指针,当您不断递增这些指针时,这些指针将从0x0FFF滚动到0x0000,因为递增电路不会将进位传播到较高字节的较低Nyble。因此,例如,如果我想执行
    while(*ptr++)
    来遍历以null结尾的字符串,那么我可能会得到
    ptr
    指向数组外部的结果

  • 在上,因为一个机器字比一个地址长,指针可能在包含地址的字的上半部分有标签和其他数据。在这种情况下,如果递增指针会导致溢出,则其他数据可能会被更改。同样的道理也适用于早期的Macintosh,在ROM还没有32位干净之前

所以我的问题是C标准是否说明了递增指针的真正含义。据我所知,C标准假定它应该以与递增整数相同的方式以位方式工作。但正如我们所看到的,这并不总是成立的

符合标准的C编译器是否可以发出一个简单的
adda0,1
2来增加指针,而不检查进位传播的存在或缺乏是否不会导致奇怪?


1:在PDP-10上,地址是18位宽,但机器字是36位宽。一个机器字可能包含两个指针(对于Lisp来说很方便)或一个指针,加上表示“添加另一级间接寻址”、段、偏移等的位字段。或者一个机器字当然可能不包含指针,但这与这个问题无关


2:在地址中添加一个。这就是68000汇编程序。

C标准对实现一无所知,标准也不关心实现。它只说明了指针算法的效果


C允许被称为未定义行为的行为。C不关心指针算法的结果是否有意义(即它不是越界的,或者实际实现定义的存储没有环绕)。如果真是这样,那就是UB。防止UB由程序员决定,而C没有任何检测或防止UB的标准机制。

指针算法的行为由C标准指定,只要结果指向有效对象或刚好经过有效对象。更重要的是,标准没有说明指针的位是什么样子的;实现可以根据自身的目的对其进行安排

因此,不,标准没有说明当指针的增量达到地址滚动的程度时会发生什么

如果所引用的
while
循环只经过数组末尾一个元素,则在C中是安全的。(根据标准,如果
ptr
已增加到数组末尾之外的一个元素,并且
x
指向数组中的任何元素,包括第一个元素,则
x
必须为true。因此,如果
ptr
已在内部滚动,则C实现负责确保比较仍然有效。)

如果你的
while
循环可能会在数组末尾之外增加
ptr
多个元素,那么C标准不会定义行为。

人们经常问,“为什么C有未定义的行为?”。这是一个很好的例子,说明了其中一个重要的原因

让我们继续使用NS SC/MP示例。如果硬件指示递增指针值
0x0FFF
不太正确,我们有两种选择:

  • 如果(p==0x0FFF)p=0x1000;否则p++;将代码翻译成等价的
    p++

  • p++
    转换为一个直接的增量,但要将其装配起来,以确保正确分配的对象不会与涉及
    0x0FFF
    的地址重叠,这样,如果有人编写的代码最终操纵指针值
    0x0FFF
    ,并向其添加一个指针值并得到奇怪的答案,您可以说“这是未定义的,所以任何事情都可能发生”


  • 如果采用方法#1,生成的代码会更大、更慢。如果采用方法#2,生成的代码效率最高。如果有人抱怨这种奇怪的行为,问为什么编译器不能生成“更合理”的代码,你可以简单地说,“我们的任务是尽可能提高效率。”。“

    很多平台都有寻址方法,这些方法无法“轻松”跨越某些边界进行索引。C标准允许实现两种通用方法来处理这一问题(可能是,但通常不是,一起使用):

  • 不要让编译器、链接器或
    malloc
    样式的函数以跨越任何问题边界的方式放置任何对象

  • 以一种可以跨任意边界索引的方式执行地址计算,即使这种方式的效率低于不能跨任意边界索引的地址计算代码

  • 在大多数情况下,方法#1将产生更快、更紧凑的代码,但代码有效使用内存的能力可能会受到限制。例如,如果代码需要许多每个33000字节的对象,那么一台具有4MB堆空间的机器将被细分为“刚性”64K块,将被限制为创建64个(每个块一个)方法#2通常会生成速度慢得多的代码,但这样的代码可能能够更有效地利用堆空间

    有趣的是,强制16位或32位对齐要求将允许许多8位处理器生成比允许任意对齐更高效的代码(因为它们可以在单词字节之间建立索引时省略跨页逻辑),但我从未见过任何8位编译器提供强制和利用这种对齐的选项