gag*_*ou7 4 c math standards pointers undefined-behavior
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?
In this example:
char test[10];
char * ptr = &test[0];
printf("test[-1] : %d", *(ptr-1))
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
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标准没有定义未定义行为的未定义程度。如果未定义,则总是下注。
另外,现代的编译器将这种指针出处弄得一团糟,在这种情况下,编译器甚至会监视是否正确导出了可能有效的指针,如果不是,则可以调整程序行为。
如果您不希望使用UB进行数学指针运算,则可以uintptr_t
在进行数学运算之前尝试将指针强制转换为。
例如:
#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);
}
Run Code Online (Sandbox Code Playgroud)
在我的机器上,使用进行编译gcc -O2
,结果为:
&a=0x7ffee4e36cae
&b=0x7ffee4e36caf
&a+1=0x7ffee4e36caf
&b+1=0x7ffee4e36cb0
0
Run Code Online (Sandbox Code Playgroud)
即,&a+1
具有与相同的数字地址,&b
但&b
由于地址是从不同的对象派生而被视为不等于。
(此gcc优化有些争议。它没有跨越函数调用/翻译单元的边界,clang并没有这样做,并且没有必要,因为6.5.9p6允许偶然的指针相等。请参见dbush到此Keith汤普森的 答案以获取更多详细信息。)