Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
Таким же образом устанавливать -1 в тип bool некорректно и он формально не будет ни true, ни false. Хотя в большинстве случаев он будет вести себя как true. В большинстве случаев…
#include <stdbool.h>
void wrong_bool_memset(){
bool b;
memset(&b, -1, 2);
printf("%d\n", (int)b);
printf("%d\n", (int)!b);
if(!b)printf("Checked\n");
}
Вывод:$ cat test.cc
int foo(bool x) {
if (x)
return 0;
else
return 42;
}
int bar(bool x) {
return (!!x) * 2;
}
$ gcc -O3 -S test.cc -o-
.file "test.cc"
.text
.p2align 4,,15
.globl _Z3foob
.type _Z3foob, @function
_Z3foob:
.LFB0:
.cfi_startproc
cmpb $1, %dil
sbbl %eax, %eax
andl $42, %eax
ret
.cfi_endproc
.LFE0:
.size _Z3foob, .-_Z3foob
.p2align 4,,15
.globl _Z3barb
.type _Z3barb, @function
_Z3barb:
.LFB1:
.cfi_startproc
movzbl %dil, %eax
addl %eax, %eax
ret
.cfi_endproc
.LFE1:
.size _Z3barb, .-_Z3barb
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4"
.section .note.GNU-stack,"",@progbits
1
— это true
, всё остальное false
, во втором вместо 0
и 2
получаем половину «таблицы менделеева». Вам достаточно?bool
ом — эта та ещё задачка. Некоторые аж в ассемблер залазят, чтобы точно всё сработало.вина того, кто использовал неявное приведения bool к int, ничуть не меньше, чем на том, кто его заполнил странным значением.С чего вдруг? Integral conversion вполне однозначно говорят:
bool
преобразованный к int
у даёт гарантированно либо 0
, либо 1
.И кроме того, следуя логики статьи, не является ли ваш пример основанием для того, чтобы отказаться от использования bool?Нет. Тут нужно просто запомнить, что
bool
кажется типом похожим на int
или char
, но на самом деле нужно относиться к нему уважительно — так, как вы относитесь к объектам. Если объект с виртуальной функций обнулить memset
ом — тоже ведь беда будет.А вот bool до «недавнего» времени вообще не существовал и инициализировать то что использовалось вместо него можно было вообще чем угодно.Вообще-то
_Bool
появился в C99 15 лет назад (а в C++ присутствовал с самого начала).есть множество граблей, на которые наступают даже опытные разработчики.
…
Не путайте местами аргументы.
memset может установить невалидное значение
Если в элементы double установить байты -1, мы получим значение Not-A-Number (NaN)
Я вот не пойму, это стеб или серьезно?Это абсолютно серьёзно. Количество проектов, в которых перепутаны аргументы memset'а просто-таки не поддаётся перечислению.
Следующей по опасности, видимо, будет операция деления: Если путать местами делимое и делитель — такая ерунда получается.Именно в этом и проблема: если вы перепутаете местами делимое и делитель, то ваша программа нормально работать не будет. А если перепутать аргументы memset'а местами — то будет. До поры, до времени. В 90% случаев последний аргумент
memset
а — нуль, если его передать вторым, то уже неважно что будет в третьем, просто обнуления не произойдёт. Сразу после запуска программы, когда вы получаете от системы «чистенькую» память — всё работает, а если немножко поработать — начинает глючить по странному. И воспроизводимости никакой нет. Очень неприятная ошибка.И это еще почти никто (@a_batyr как-то неуверенно это сделал) не упомянул какой кошмар начнется если memset-ом начинать заполнять случайные области на стеке!Действительно. А дело всё в том, что тут речь идёт не о каких-то «фантазиях на тему», а про наиболее неприятные ошибки, к которым приводит
memset
. Если вы начинаете заполнять «случайные области на стеке», то ваша программа долго не проживёт, вы эту ошибку заметите и исправите. Всё. Неприятно, но не смертельно. А вот ошибки, которые могут сидеть в коде годами и проходить при этом разные тесты — это действительно неприятно. Структура memset
'а такова, что это происходит довольно-таки часто: либо ничего не обнуляется, либо обнуляется слишком мало — заметить это сложно на практике (когда обнуляется слишком много — это как раз обычно сразу замечают).В 90% случаев последний аргумент memsetа — нуль
memset — сторона тьмы