elglin: (Default)
[personal profile] elglin
https://habr.com/company/pvs-studio/blog/418023/

int main(void) {
    int a, b;
    int *p = &a;
    int *q = &b + 1;
    printf("%p %p %d\n", (void *)p, (void *)q, p == q);
    return 0;
}


И в статье (переводной) задаются вопросом, почему этот код странно работает? Ответ простой - потому что он мудацкий. То есть обычно оно все даже прокатит и заработает, потому что в архитектуре x86 a и b лягут последовательно в стек, причем, поскольку компилятор читает слева направо, именно в нужном порядке.
Но, е-мое, a и b могут лежать вообще где и как угодно, и никто не гарантирует, как именно.
Хотите устраивать подобную указательную магию, используйте int a[2], а вот тогда стандарт гарантирует, что &(a[1]) == a + 1, потому что a[n] можно считать синтаксическим сахаром для *(a + n).

Вот отсюда, блин, и идет дурная слава Си - от товарищей, которые устраивают пляски с указателями по принципу "прокатило". Умные люди вообще советуют не использовать указательную арифметику, несмотря на элегантность всяких *p++ = *q++.

Что до печальки на тему того, что компилятор вольно трактует сравнение неизвестных ему extern int* start и extern int* end - так кошерно передавать не начало и конец буфера, а начало и длину. Разница между for(p = start; p < end; p++) и end = start + n; for(p = start; p < end; p++) в одно слово и один-два такта (ADD или ADD + TFR/XCHG) - я могу представить себе случаи, когда это критично, но даже 20 лет назад в этом уже большого смысла не было.
Page generated Jan. 22nd, 2026 11:58 pm
Powered by Dreamwidth Studios