关于数组外部指针算术的C标准 [英] C standard regarding pointer arithmetic outside arrays

查看:53
本文介绍了关于数组外部指针算术的C标准的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我读了很多有关指针算术和未定义行为的内容(链接链接链接

I read lot of things about pointer arithmetic and undefined behavior (link, link, link, link, link). It always ends up to the same conclusion: Pointer arithmetic is well defined only on array type and between array[0] and array[array_size+1] (one element past the end is valid with regard to the C standard).

我的问题是:这是否意味着当编译器看到与任何数组都不相关的指针算术(未定义的行为)时,它可能会发出所需的内容(甚至什么也没有)?还是更高级别的未定义行为",意味着您可以访问未映射的内存,垃圾数据等,并且不能保证地址的有效性?

My question is: Does it means that when the compiler sees a pointer arithmetic not related to any array (undefined behavior), it could emit what it want (even nothing) ? Or is it more a high level "undefined behavior" meaning you could reach unmapped memory, garbage data, etc and there is not guarantee about the address validity?

在此示例中:

char test[10];
char * ptr = &test[0];
printf("test[-1] : %d", *(ptr-1))

通过未定义的行为",仅仅是该值根本无法保证(可能是垃圾,未映射的内存等),但我们仍然可以肯定地说我们正在访问与数组8字节相邻的内存地址开始之前?还是未定义的行为"以某种方式使编译器根本无法发出此代码?

By "undefined behavior", is it just that the value is not guarantee at all (could be garbage, unmapped memory, etc) but we can still say with certainty that we are accessing the memory address contiguous to the array 8 bytes before the start? Or is it "undefined behavior" in a way that the compiler can just not emit this code at all?

另一个简单的用例:您要计算一个函数的内存大小.一个简单的实现可能是下面的代码,假设这些函数以相同的顺序在二进制文件中输出,并且是连续的并且之间没有任何填充.

Another simple use case: You want to compute the in-memory size of one function. One naïve implementation could be the following code assuming that the functions are outputted in the binary in the same order, are contiguous and without any padding in between.

#include <stdint.h>
#include <stdio.h>

void func1()
{}

void func2()
{}

int main()
{
  uint8_t * ptr1 = (uint8_t*) &func1;
  uint8_t * ptr2 = (uint8_t*) &func2;

  printf("Func 1 size : %ld", ptr2-ptr1);

  return 0;
}

由于 ptr1 ptr2 不是数组的一部分,因此将其视为未定义的行为.同样,这是否意味着编译器无法发出这些代码?还是不确定行为"意味着减法是没有意义的,取决于系统(函数在内存中不连续,带有填充等),但仍会按预期发生?是否存在定义明确的方法来计算两个不相关的指针之间的减法?

Since ptr1 and ptr2 are not part of an array, it is considered as undefined behavior. Again, does it means the compiler could not emit those code? Or does "undefined behavior" means that the subtraction is meaningless depending on the system (functions not contiguous in memory, with padding, etc) but still occurs as expected? Is there any well defined way to compute the subtraction between two unrelated pointers?

推荐答案

C标准未定义未定义行为的未定义程度.如果未定义,则总是下注.

The C standard doesn't define degrees of undefinedness for undefined behavior. If it's undefined, it's always all bets are off.

此外,现代编译器还弄乱了这种指针出处,在这种情况下,编译器甚至会监视是否正确导出了可能有效的指针,如果不是,则可以调整程序行为.

Additionally, modern compilers mess with this pointer provenance thing where the compiler even watches if a possibly valid pointer is derived correctly and if it isn't, it can adjust program behavior.

如果您希望数学指针算术没有UB的可能性,您可以在进行数学运算之前尝试将指针投射到 uintptr_t 上.

If you want mathematical pointer arithmetic without the possibility of UB, you can try and cast your pointer to uintptr_t prior to doing the math.

例如:

#include <stdio.h>
int main()
{
    char a,b;
    printf("&a=%p\n", &a);
    printf("&b=%p\n", &b);
    printf("&a+1=%p\n", &a+1);
    printf("&b+1=%p\n", &b+1);
    printf("%d\n", &a+1==&b || &b+1==&a);
}

在我的计算机上,用 gcc -O2 编译的

结果为:

on my machine, compiled with gcc -O2, results in:

&a=0x7ffee4e36cae
&b=0x7ffee4e36caf
&a+1=0x7ffee4e36caf
&b+1=0x7ffee4e36cb0
0

即,& a + 1 具有与& b 相同的数字地址,但被视为与& b 不相等,因为地址是从不同的对象派生的.

I.e., &a+1 has the same numerical address as &b but is treated as unequal to &b because the addresses are derived from different objects.

(这种gcc优化有些争议.它没有跨越函数调用/翻译单元的边界,clang并没有这样做,因此不必使用 dbush 指向此基思·汤普森的 answer 了解更多详细信息.)

(This gcc optimization is somewhat controversial. It doesn't carry across function call / translation unit boundaries, clang doesn't do it, and it's not necessary as 6.5.9p6 does allow for accidental pointer equality. See dbush's to this Keith Thompson's answer for more details.)

这篇关于关于数组外部指针算术的C标准的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆