Это проходит glibc, который выпускает прерывание 0x80 после заполнения регистров с параметрами. Обработчик прерываний ядра затем ищет syscall в syscall таблице и вызывает соответствующий sys_ * () функция.
Все вышеперечисленное. Я использую:
На самом деле, я просто преувеличиваю. Это не так уж плохо, и на самом деле не так уж сложно сохранить контроль над ресурсами, если вы правильно структурируете свой код.
Интересное примечание. У меня есть большое приложение, которое использует DCOM и имеет управляемые и неуправляемые модули. Неуправляемые модули, как правило, труднее отлаживать во время разработки, но они очень хорошо работают на сайте заказчика из-за большого количества выполняемых на нем тестов.
Не менее актуально - как вы убедитесь, что ваши файлы и сокеты закрыты, ваши блокировки сняты, yada yada. Память - не единственный ресурс, и с GC вы по своей сути теряете надежное / своевременное уничтожение.
Ни GC, ни не-GC автоматически не превосходят. У каждого есть свои преимущества, у каждого своя цена, и хороший программист должен уметь справиться с обоими.
Я сказал об этом в ответе на этот вопрос .
Я использую C ++ 10 лет. Я использовал C, Perl, Lisp, Delphi, Visual Basic 6, C #, Java и различные другие языки, которые я не могу припомнить.
Ответ на ваш вопрос прост: вы должны знать, что делаете , больше, чем C # / Java. больше, чем - вот что порождает такие разглагольствования, как Джефф Этвуд относительно «Школы Java» .
Большинство ваших вопросов в некотором смысле бессмысленны. «Проблемы», которые вы поднимаете, - это просто факты того, как аппаратное обеспечение действительно работает . Я бы хотел попросить вас написать ЦП и ОЗУ на VHDL / Verilog и посмотреть, как все работает на самом деле, даже когда действительно упрощено. Вы' Я начну понимать, что способ C # / Java - это абстракция, связывающая аппаратное обеспечение.
Более простой задачей было бы запрограммировать элементарную операционную систему для встроенной системы с момента первого включения; он также покажет вам, что вам нужно знать.
(Я также написал C # и Java)
Я использую много-много утверждений и создаю как «отладочную», так и «выпускную» версию. Моя отладочная версия работает намного медленнее, чем моя окончательная версия, со всеми ее проверками.
Я часто запускаю под Valgrind , и мой код не имеет утечек памяти. Нуль. Гораздо проще сохранить программу без утечек, чем взять программу с ошибками и исправить все утечки.
Кроме того, мой код компилируется без предупреждений, несмотря на то, что у меня есть компилятор, настроенный на дополнительные предупреждения. . Иногда предупреждения выглядят глупо, но иногда они указывают прямо на ошибку, и я исправляю ее без необходимости искать ее в отладчике.
Я пишу чистый C (я не могу использовать C ++ в этом проекте), но я делаю C очень последовательно. У меня есть объектно-ориентированные классы с конструкторами и деструкторами; Приходится вызывать их вручную, но последовательность помогает. И если я забываю вызвать деструктор, Valgrind бьет меня по голове, пока я не исправлю его.
В дополнение к конструктору и деструктору я пишу функцию самопроверки, которая просматривает объект и решает, является ли он нормальным или не; например, если дескриптор файла равен нулю, но связанные с ним данные файла не обнулены, это указывает на какую-то ошибку (либо дескриптор затерт, либо файл не был открыт, но в этих полях объекта есть мусор). Кроме того, у большинства моих объектов есть поле «подпись», в котором должно быть установлено определенное значение (специфичное для каждого отдельного объекта). Функции, использующие объекты, обычно утверждают, что объекты нормальны.
Каждый раз, когда я malloc ()
немного памяти, моя функция заполняет память значениями 0xDC
. Структура, которая не полностью инициализирована, становится очевидной: счетчики слишком велики, указатели недействительны ( 0xDCDCDCDC
), и когда я смотрю на структуру в отладчике, становится очевидно, что она не инициализирована. Это намного лучше, чем заполнение памяти нулями при вызове malloc ()
. (Конечно, заливка 0xDC
есть только в отладочной сборке; нет необходимости для сборки выпуска тратить это время.)
Каждый раз, когда я освобождаю память, я стираю указатель. Таким образом, если у меня есть глупая ошибка, когда код пытается использовать указатель после того, как его память была освобождена, я мгновенно получаю исключение с нулевым указателем, которое указывает мне прямо на ошибку. Мои функции деструктора не принимают указатель на объект, они принимают указатель на указатель и стирают указатель после разрушения объекта. Также, деструкторы стирают свои объекты перед их освобождением, поэтому, если какой-то фрагмент кода имеет копию указателя и пытается использовать объект, утверждение проверки работоспособности срабатывает немедленно.
Valgrind сообщит мне, если какой-либо код записывает конец буфер. Если бы у меня этого не было, я бы поставил «канареечные» значения после концов буферов и проверил их при проверке работоспособности. Эти канареечные значения, как и значения подписи, будут использоваться только для отладки, поэтому в версии выпуска не будет раздувания памяти.
У меня есть набор модульных тестов, и когда я вношу какие-либо серьезные изменения в код, он очень удобно запускать модульные тесты и быть уверенным, что я ничего ужасно не сломал. Конечно, я запускаю модульные тесты как для отладочной, так и для окончательной версии, поэтому у всех моих утверждений есть шанс найти проблемы.
Установка всей этой структуры на место потребовала дополнительных усилий, но они окупаются каждый день. И я чувствую себя вполне счастливым, когда срабатывает assert и указывает мне прямо на ошибку, вместо того, чтобы запускать ошибку в отладчике. В конечном итоге, просто поддерживать все время в чистоте меньше работы.
Наконец, я должен сказать, что мне действительно нравится венгерская нотация. Я работал в Microsoft несколько лет назад и, как и Джоэл, выучил Apps венгерский, а не сломанный вариант. Это действительно делает неправильный код неправильным .
Должен сказать, что мне действительно нравятся венгерские обозначения. Я работал в Microsoft несколько лет назад и, как и Джоэл, выучил Apps венгерский, а не сломанный вариант. Это действительно делает неправильный код неправильным . Должен сказать, что мне действительно нравятся венгерские обозначения. Я работал в Microsoft несколько лет назад и, как и Джоэл, выучил Apps венгерский, а не сломанный вариант. Это действительно делает неправильный код неправильным .Мы пишем на C для встраиваемых систем. Помимо использования некоторых методов, общих для любого языка программирования или среды, мы также используем:
Я написал и C ++, и C #, и я не вижу всей шумихи вокруг управляемого кода.
Да ладно, есть сборщик мусора для памяти, это полезно ... если, конечно, вы не воздержитесь от использования простых старых указателей в C ++, если вы используете только smart_pointers, у вас не будет так много проблем.
Но тогда я бы хотел знать. .. ваш сборщик мусора защищает вас от:
Управление ресурсами - это гораздо больше, чем управление памятью. Хорошая вещь в C ++ заключается в том, что вы быстро узнаете, что означает управление ресурсами и RAII, так что это становится рефлексом:
Что касается переполнения буфера, ну, это не похоже на то, что мы используем char * и size_t везде. У нас есть некоторые вещи, называемые 'string', 'iostream' и, конечно же, уже упомянутый метод vector :: at, который освобождает нас от этих ограничений.
Протестированные библиотеки (stl, boost) хороши,
Помимо множества полезных советов, приведенных здесь, моим самым важным инструментом является СУХОЙ - Не повторяйся. Я не распространяю код, подверженный ошибкам (например, для обработки выделения памяти с помощью malloc () и free ()) по всей моей кодовой базе. В моем коде есть ровно одно место, где вызываются malloc и free. Он находится в функциях-оболочках MemoryAlloc и MemoryFree.
Здесь есть все проверки аргументов и начальная обработка ошибок, которая обычно дается как повторяющийся шаблонный код вокруг вызова malloc. Кроме того, он позволяет все, что требует изменения только одного местоположения, начиная с простых проверок отладки, таких как подсчет успешных вызовов malloc и free и проверка при завершении программы, что оба числа равны, вплоть до всевозможных расширенных проверок безопасности.
Иногда, когда я читаю здесь вопрос вроде «Я всегда должен следить за тем, чтобы strncpy завершал строку, есть ли альтернатива?»
strncpy(dst, src, n);
dst[n-1] = '\0';
, за которой следовали дни обсуждения, я всегда задавался вопросом, является ли искусство извлечения повторяющейся функциональности в функции потерянным искусством о высшем программировании, которое больше не преподается на лекциях по программированию.
char *my_strncpy (dst, src, n)
{
assert((dst != NULL) && (src != NULL) && (n > 0));
strncpy(dst, src, n);
dst[n-1] = '\0';
return dst;
}
Основная проблема дублирования кода решена - теперь давайте подумаем, действительно ли strncpy является правильным инструментом для работы. Спектакль? Преждевременная оптимизация! И еще одно место для начала после того, как оно окажется узким местом.
Мне всегда интересно, является ли искусство извлечения повторяющейся функциональности в функции утерянным искусством высшего программирования, которое больше не преподается на лекциях по программированию.char *my_strncpy (dst, src, n)
{
assert((dst != NULL) && (src != NULL) && (n > 0));
strncpy(dst, src, n);
dst[n-1] = '\0';
return dst;
}
Основная проблема дублирования кода решена - теперь давайте подумаем, действительно ли strncpy является правильным инструментом для работа. Спектакль? Преждевременная оптимизация! И еще одно место для начала после того, как оно окажется узким местом.
Мне всегда интересно, является ли искусство извлечения повторяющейся функциональности в функции утерянным искусством высшего программирования, которое больше не преподается на лекциях по программированию.char *my_strncpy (dst, src, n)
{
assert((dst != NULL) && (src != NULL) && (n > 0));
strncpy(dst, src, n);
dst[n-1] = '\0';
return dst;
}
Основная проблема дублирования кода решена - теперь давайте подумаем, действительно ли strncpy является правильным инструментом для работа. Спектакль? Преждевременная оптимизация! И еще одно место для начала после того, как оно окажется узким местом.
В C ++ есть все упомянутые вами функции.
Есть управление памятью. Вы можете использовать интеллектуальные указатели для очень точного управления. Или есть несколько доступных сборщиков мусора, хотя они не являются частью стандарта (но в большинстве случаев смарт-указатели более чем подходят)
C ++ - язык со строгой типизацией. Прямо как C #.
Мы используем буферы. Вы можете выбрать версию интерфейса с проверкой границ. Но если вы знаете, что проблем нет, вы можете использовать непроверенную версию интерфейса.
Сравнить метод at () (отмечен) с оператором [] (не отмечен).
Да, мы используем модульное тестирование . Точно так же, как вы должны использовать C #.
Да, мы осторожные программисты. Точно так же, как вы должны быть в C #. Единственная разница в том, что подводные камни в двух языках разные.
Ответ Эндрю хороший, но я бы также добавил дисциплины в список. Я обнаружил, что после достаточной практики с C ++ вы довольно хорошо понимаете, что безопасно, а что просит велоцирапторов съесть вас. Вы склонны развивать стиль кодирования, который будет удобен при следовании безопасным методам и оставит у вас чувство хиби-джиби, если вы попытаетесь, скажем, вернуть умный указатель обратно на необработанный указатель и передать его чему-то другому.
I Мне нравится думать об этом как об электроинструменте в магазине. Это достаточно безопасно, если вы научитесь правильно им пользоваться и при условии, что вы всегда соблюдаете все правила безопасности. Вы получаете травму, когда думаете, что можете отказаться от защитных очков.