«Цель OPN [Отладка] отменяет настройку сборки OTHER_LDFLAGS». Это был главный вопрос. После добавления $ (унаследованного) в новой строке в других флагах компоновщика решена моя проблема.
Описание компоновщика. Любой, кто использует C, должен понимать, почему "static int x;" в области видимости файла не создает глобальную переменную. Упражнение по написанию простой программы, где каждая функция находится в своей собственной единице трансляции и компилируется каждая отдельно, выполняется недостаточно часто на ранних этапах изучения C.
Просмотрите весь жизненный цикл программирования, включая то, что происходит с вашим кодом после того, как вы его закончили .
Я думаю, что общая идея кажется действительно хорошей. Это еще кое-что.
Надеюсь, этого раньше не публиковали (просто прочтите очень быстро), но я думаю, что очень важно, когда вам нужно работать с C, - это знать о машинном представлении данных. Например: числа с плавающей запятой IEEE 754, обратный порядок байтов от старшего к младшему, выравнивание структур (здесь: Windows против Linux) ... Чтобы попрактиковаться в этом, очень полезно составить несколько бит-головоломок (решение некоторых проблем без использования каких-либо функций, а затем printf для печати результата, ограниченное количество переменных и некоторые логические операторы). Также часто бывает полезно иметь базовые знания о том, как работает компоновщик, как работает весь процесс компиляции и т. Д. Но особенно разбираться в компоновщике (без этого так сложно найти какие-то ошибки ...)
Книга, которая больше всего помогла мне улучшить мои навыки C и C ++, была: http://www.amazon.com/Computer-Systems-Programmers-Randal-Bryant/dp/013034074X
Я думаю, что глубокий знание компьютерной архитектуры определяет разницу между хорошим и плохим программистом на C (или, по крайней мере, это существенный фактор).
Как насчет общих передовых практик?
Большинство функций должны возвращать статус
[Другим: не стесняйтесь редактировать это и добавлять в список]
Относительно проверки входных данных:
Однажды я в спешке написал большую программу и написал всевозможные защитные оговорки, проверки ввода, в мои функции. Когда я запускал программу в первый раз, ошибки из этих предложений передавались так быстро, что я даже не мог их прочитать, но программа не аварийно завершилась и ее можно было полностью закрыть. После этого нужно было просто просмотреть список и исправить ошибки, которые прошли на удивление быстро.
Думайте о предохранительных предложениях как о предупреждениях и ошибках компилятора во время выполнения.
Отладчик - ваш друг. В языке C легко ошибиться, и лучший способ понять свои ошибки - часто видеть их в отладчике.
Было бы полезно, если бы учащиеся в какой-то момент познакомились с инструментами, которые могут помочь им писать чище, лучший код. Не все инструменты могут иметь отношение к ним на данном этапе, но знание того, что доступно, помогает.
Следует также подчеркнуть использование разных (!) Компиляторов со строгими флажками предупреждения компилятора и вниманием к каждому и каждому предупреждающее сообщение.
Один Следует также подчеркнуть использование разных (!) компиляторов со строгими флагами предупреждений компилятора и внимания к каждому предупреждающему сообщению.
Один Следует также подчеркнуть использование разных (!) компиляторов со строгими флагами предупреждений компилятора и внимания к каждому предупреждающему сообщению.
Заключите все параметры макроса в круглые скобки.
Если макрос является оператором, более сложным, чем присвоение или вызов функции, заключите его следующим образом:
#define M(A) do { ... (A) ... } while (0)
Никогда не верьте компилятор. Обычно правильно, что есть проблема, но, за исключением самых тривиальных ошибок, почти всегда неверно, в чем проблема и где она находится.
ПРИМЕЧАНИЕ: Я не сказал игнорировать компилятор. Я сказал, не верь этому. Он знает, что есть проблема, но часто ошибается в том, что именно. Принимать выходные данные компилятора за чистую монету - это рецепт разочарования и траты времени. Особенно для сложных ошибок.
Мои лекторы время от времени говорили о производительности, но никогда не упоминали стоимость ветвления по сравнению с другими операциями. Я понял это только позже, когда изучал микропроцессоры. Так много раз мы делаем ненужные ветки, когда ту же проблему можно решить с помощью побитовых манипуляций, например, нахождения позиции буквы в алфавите:
if (islower(letter)) {
pos = letter - 'a' + 1;
} else if (isupper(letter)) {
pos = letter - 'A' + 1;
}
vs:
pos = letter & 31;
конечно, ascii был разработан с таким видом о чем-то задуманном, так что показ этого не значит, что мы научились бы «плохому стилю» или каким-то «волшебным приемам» ... Теперь я каждый день использую побитовые уловки, чтобы избежать ветвления.
- мои 2 цента
Я очень рад сказать, что меня учили почти всему остальному, что здесь уже упоминалось (включая модульное тестирование и шаблоны ООП в C, правда!).
#pragma
, может использоваться для передачи дополнительной информации процессору. Я работал над процессорами TI с языком C, и это очень помогло мне в определении сегментов памяти.
Также '__ FILE__' и '__LINE__'
предопределенные макросы очень полезны при отладке / ведении журналов, но я никогда этого не знал. Такие вещи нужно рассказывать студентам.
Помимо очевидных указателей, я обнаружил, что никто не говорит о запятых, когда я изучал C.
a= 1, b= 2;
Конечно, вы используете его внутри операторов for (;;) {}, но никто никогда не понимал почему, и я никогда не видел, чтобы кто-то еще использовал это, кроме операторов for.
Но C
обрабатывает запятые иначе, чем точки с запятой. Например:
"if (a) b = a, c = a;"
то же самое, что
"if (a) { b = a; c= a; }"
, но отличается от
"if (a) b = a; c = a;
. Я не говорю, что первая форма с запятыми лучше, потому что это сбивает с толку программистов, которые не знают лучшего, и будет трудно увидеть, используете ли вы очень мелкие шрифты, но бывают случаи, когда вы можете столкнуться с таким кодом, и полезно знать, что на самом деле делает язык.
Кроме того, я обнаружил, что если у меня есть много инициализации в верхней части функции,
a = 1,
b = 2,
i1 = 0,
i2 = 0,
i3 = 0,
i4 = 0,
dtmp = 0.0,
p = strtmp;
Разделение всех этих назначений запятыми делает их одним оператором и позволяет мне «пройти» в отладчике все из них за один шаг вместо восьми (или более). Да, современные графические интерфейсы делают установку точки останова и переход между ними менее болезненными, но одно действие (шаг) по-прежнему трудно превзойти.
Компилятор не всегда прав. Особенно при разработке для встраиваемых систем.
Концепции порядка выполнения и точек последовательности довольно полезны и мало обсуждаются.
Полезно знать, что x = x ++; вызывает неопределенное поведение. Знание , почему это может быть намного более познавательным.
Учитывая вашу аудиторию, может быть полезно некоторое обсуждение «изменчивости», а также других концепций взаимодействия с оборудованием. Как обрабатывать регистры только для записи и тому подобное.
Указатель - это не что иное, как тип данных для хранения адресов , точно так же, как int - это тип данных для хранения целых чисел. Когда я усвоил это, все, что касалось указателей и арифметики указателей, стало на свои места.
Моделирование объектов с помощью структур и указателей функций
Хорошие концепции переносимого кодирования, модели программирования (например, ILP32 по сравнению с LP64) и предоставление их различным компиляторам C и инструментальным средствам (не во всем мире используется GCC).
Одна вещь, которую я хотел бы, чтобы преподавали больше профессоров программирования, это немного об управлении исходным кодом. День на любой VCS: почему вы его используете, некоторые простые операции, нумерация версий и т. Д.
Слишком много выпускников считают управление версиями чужеродной концепцией ... это не имеет значения что они специализируются на EE или CS, если они пишут код, им следует немного знать о системах контроля версий.