- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
int main(void)
{
char a[8], b[8];
char *a_ptr = a+8;
char *b_ptr = b;
printf("a_ptr = %p, b_ptr = %p\n", a_ptr, b_ptr);
if (a_ptr != b_ptr)
{
printf("a_ptr != b_ptr\n");
}
else
{
printf("a_ptr == b_ptr\n");
}
if ((uintptr_t)a_ptr != (uintptr_t)b_ptr)
{
printf("(uintptr_t)a_ptr != (uintptr_t)b_ptr\n");
}
else
{
printf("(uintptr_t)a_ptr == (uintptr_t)b_ptr\n");
}
return EXIT_SUCCESS;
}
> Two pointers compare equal if and only if both are null pointers, both are pointers to the same object(including a pointer to an object and a subobject at its beginning) or function, both are pointers to one past the last element of the same array object, or one is a pointer to one past the end of one array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space. .111)
> 111)Two objects may be adjacent in memory because they are adjacent elements of a larger array or adjacent members of a structure with no padding between them, or because the implementation chose to place them so, even though they are unrelated. If prior invalid pointer operations (such as accesses outside array bounds) produced undefined behavior, subsequent comparisons also produce undefined behavior.
1)gcc и clang печатают разные адреса и, соответственно, сообщение о том что не равны и так, и эдак справедливо.
2)vc проработав секунд 10, не печатает ничего.
Более того, согласно приведенному тобой стандарту, "or because the implementation chose to place them so, even though they are unrelated"
Каким компилятором ты пользовался?
в
Потому что он видит что у указателей разное "происхождение", и ему становится похуй.
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61502#c30
Вот в S" Forth" все оптимизации делает программист, именно поэтому я за S" Forth". вот эт было бы другое дело.
Вот так, например, можно:
Введите название языка: Forth >ok
о да, это один из главных минусов. Потому и пишут стековые диаграммы, я даже в сложных случаях на каждой строчке их пишу. Можно облегчить страдания если стараться писать маленькие определения, ещё облегчают дело LOCALS|
А адреса глобальных переменных могут быть constexpr? Допустим, что программа может загружаться по произвольному адресу, но при этом смещения глобальных объектов относительно начала образа фиксированы.
Кстати, нашёл не очень старое говно:
http://govnokod.ru/24539
Забавно, что 25349 получается из 24359 перестановкой цифр.
Для пирфоманса компиляторы выравнивают данные, между переменными появляются неиспользуемые промежутки. Способ выравнивания может зависеть от флагов оптимизации.
2. Я чуть выше написал про предварительное выделение памяти в стеке и про push. Предварительное выделение и push приводят к размещению локальных переменных в противоположных порядках.
3. Часть локальных переменных компилятор может утоптать в регистры, чтобы не тратить память.
*****
Да, компилятор знает, как он это будет делать. Но у «gcc», вероятно, проблема из-за его кроссплатформенности. Нужно поддерживать кучу рахит-тинктур. Парсер, оптимизатор, кодогенератор разделены. Чтобы они могли сообщать друг другу дополнительную информацию, нужны хаки.
Зачем смешивать способы выделения?
В «Паскале» выделять переменные можно только в самом начале функции. Там всё просто: сразу выделил место в стеке и разместил подряд в прямом порядке.
В «C99» и в «C++» переменные можно выделять в операторе «for» и в некоторых других. Они могут занимать место в стеке временно, ведь они вне блока не используются (использовать их вне блока –— UB), поэтому их можно пушить. И вот это приводит к перемешиванию адресов.
Итого: взятие адреса локальной переменной –— это довольно небезопасная операция, выносящая мозг оптимизатору.
С глобальными переменными проще: они как правило размещаются в прямом порядке и в регистрах не хранятся. Но даже тут можно нарваться на паддинги: кококомпилятор может выравнивать переменные по-разному, в зависимости от параметров оптимизации.
GCC has a somewhat aggressive interpretation on the standard, so it compiles p == q to false if it determines that they are derived from different objects (see GCC bug 61502 for details). This has the fun effect that it is possible to get pointers p and q that point at the same memory address, but p == q evaluates to false, as in
that prints
0x7f7fffffdafc 0x7f7fffffdafc 0
on my development machine when compiled with a recent GCC.
При разных значениях параметра оптимизации они могут разместить x и y на разном расстоянии друг от друга, но всегда возвращают правильный результат (p == q, если нет дыр, и p != q, если есть дыры). «GCC» же всегда возвращает p != q вне зависимости от того, как реально размещены x и y.
gcc без оптимизации: Что ж, всё верно: p≠q, p>q.
gcc -O2: Получилось, что p не больше q, p не меньше q, но p и не равно q. Как будто сравнили два NaN.
Итог (gcc -O2):
Итак, p <= q; p >= q; p - q == 0, но при этом p != q.
Правда, пока не знаю, в каком коде это можно применить.