Да, я что-то стормозил. Простой пример по первому пункту:
bool DidSomething(void) { char* p = malloc(1); if (p) { // do something with *p free(p); } return p != NULL; }
Ты типа думаешь, что если память выделилась, всё было сделано и потом она освободилась, то можно использовать значение указателя послее free() как индикатор успеха.
Компилятор же может подумать, что если условие и тело if не выполняются, то нужно вернуть false ((NULL != NULL) == false). А если выполняются, то поскольку имеет место UB (использование указателя p после free(p)), можно не генерировать код для проверки p != NULL, а вместо этого так же всегда возвращать false. Упс.
Компилятор же может подумать...А если выполняются... то поскольку имеет место UB (использование указателя p после free(p))
Это какой компилатор такое может подумать? Гипотетический, принимая решение, как генерить код на основании вызова некоторой функции, которая, к тому же, одинарный указатель принимает, а не адрес от той указательной переменной? Ты как компиляторо-писатель хорошо понимаешь, что в переменной указательного типа p не так много дополнительных смыслов.
Да тот же gcc запросто может так подумать. Он знает, что это не какая-то там левая ф-ция, а ф-ция стандартной библиотеки с известным поведением. Т.е. ему не нужно даже пытаться смотреть на значение p. Если был вызов free(p), то согласно стандарту с p больше ничего делать нельзя, кроме как присваивать ему новое значение или брать евоный адрес, что даёт компилятору полное право не генерировать код согласно твоему исходнику.
На досуге скомпилируй в ассемблер hello-o-world программу с выражением printf("hw!\n") (опции -c -S у gcc). Загляни в асм. Там на самом деле будет вызов puts("hw!").
Reply
bool DidSomething(void)
{
char* p = malloc(1);
if (p)
{
// do something with *p
free(p);
}
return p != NULL;
}
Ты типа думаешь, что если память выделилась, всё было сделано и потом она освободилась, то можно использовать значение указателя послее free() как индикатор успеха.
Компилятор же может подумать, что если условие и тело if не выполняются, то нужно вернуть false ((NULL != NULL) == false). А если выполняются, то поскольку имеет место UB (использование указателя p после free(p)), можно не генерировать код для проверки p != NULL, а вместо этого так же всегда возвращать false. Упс.
Reply
Это какой компилатор такое может подумать? Гипотетический, принимая решение, как генерить код на основании вызова некоторой функции, которая, к тому же, одинарный указатель принимает, а не адрес от той указательной переменной? Ты как компиляторо-писатель хорошо понимаешь, что в переменной указательного типа p не так много дополнительных смыслов.
Reply
На досуге скомпилируй в ассемблер hello-o-world программу с выражением printf("hw!\n") (опции -c -S у gcc). Загляни в асм. Там на самом деле будет вызов puts("hw!").
Reply
Leave a comment