Что должен знать программист на Си? [закрыто]


12

Какие понятия / методики / особенности языка должны знать / знать каждый приличный программист на Си (исключая общую разработку программного обеспечения и тому подобное и сосредотачиваясь только на специфических для Си вещах). Я хотел бы знать, чтобы я мог заполнить некоторые возможные пробелы в моих знаниях C.


9
Начните с вопросов C о переполнении стека и посмотрите, есть ли что-то, чего вы не знаете.
chrisaycock

3
Программист переменного тока, вероятно, должен это знать2 + 2 = 4
Эдвард Стрендж,

21
Они должны знать о магазине, который продает пуленепробиваемую обувь.
Адам Кроссленд

1
На эту тему написаны сотни книг. Ваш вопрос действительно довольно расплывчатый. Вам нужно быть более конкретным, чтобы получить достойные ответы, а не просто список вещей. И, видя ответы, порожденные так далеко от этого вопроса, я бы подумал, что его нужно переработать или закрыть.
Уолтер

2
Еще один язык программирования?
Мухаммед Алкарури

Ответы:


19

Специфично для C? Помимо стандартных конструкций, общих для большинства процедурных языков, я должен сказать:

  • (ab) использование препроцессора
  • компоновщик против компилятора
  • Указатели указатели указатели!
  • Как массивы указатели являются массивами
  • Как работают строки C и как они также являются указателями и массивами
  • Как неправильное использование строки C может привести к переполнению буфера
  • Как привести что-либо к чему-либо (все это только 1 и 0 в конце концов :))
  • Ручное управление памятью malloc / free
  • Стек против Кучи
  • Псевдоним указателя, (почему это незаконно в C99)
  • Думая о разработке с точки зрения модулей (файлы .h / .c) с набором открытых функций вместо строго классов
  • Союзы
  • Почему спринтф может сбить вашу ногу
  • Функциональные указатели

Я бы добавил «переполнение буфера» в список.
Эйдан Калли

@ Эйдан, хороший улов. Добавлен.
Дуг Т.

2
Как C-массивы и указатели не совпадают: books.google.ca/…
Matthieu

указатели должны были повторяться как минимум в 3 раза больше
Гаурав

8

Разберитесь с указателями, и вы поймете компьютеры.


12
Нет, у тебя просто появится иллюзия, что ты понимаешь компьютеры.
Работа

5

В дополнение к отличному ответу Пифагра,

как написать (или хотя бы прочитать) сложные объявления, такие как char (*(*funcs[4])())[10]

funcs - это массив [4] указателей на функцию, возвращающую указатель на массив [10] типа char


1
Если это становится настолько сложным, возможно это принадлежит комментарию?
Работа

7
может, ему стоит научиться избегать такого письма?
FabianB

3
  1. Целочисленные правила продвижения
  2. Инициализируйте все к известному значению
  3. GOTO не является злом, особенно когда используется для обработки исключений / сбоев
  4. malloc и / или calloc могут возвращать NULL ... убедитесь, что ваша проверка возвращает значения
  5. Частые небольшие выделения памяти могут вызвать фрагментацию в куче.
  6. Арифметика указателей
  7. Битовые маски - твой друг
  8. x >> 1 эквивалентно x / 2 для целых чисел без знака

+1 за GOTO не злой :)
zvrba

2

Программист должен знать ... другие языки! ;-) Всегда полезно знать понятия из других языков различных парадигм, таких как ООП, функциональное программирование и так далее.

А если серьезно, посмотреть на запутанный конкурс по программированию - это весело и, что любопытно, тоже хороший опыт.


2

Я упомянул «переполнение буфера» в комментарии к ответу Пифагра, наверное, мне следует уточнить, что я имел в виду. В C недостаточно знать, что работать непосредственно с памятью опасно - вы также должны понимать, как это опасно. Мне не очень нравится метафора «стреляй себе в ногу» во всех этих случаях - большую часть времени это не то, что ты нажимаешь на спусковой крючок, но часто это актер, интересы которого противоречат твоим и / или твоим пользователям ». ,

Например, в архитектуре с нисходящим стеком (большинство популярных архитектур соответствуют этому требованию - как правило, x86 и ARM включены), когда вы вызываете функцию, адрес возврата для функции будет помещен в стек после локальных переменных, определенных в Тело функции. Поэтому, если вы объявите буфер как локальную переменную и откроете эту переменную для внешнего мира, не проверяя переполнение буфера, вот так:

void myFn(void) {
    char buf[256];
    gets(buf);
}

внешний пользователь может отправить вам строку, которая перезаписывает адрес возврата из стека - в основном, он может изменить представление вашей программы во время выполнения графа вызовов, который приводит к текущей функции. Таким образом, пользователь дает вам строку, которая является двоичным представлением некоторого исполняемого кода для вашей архитектуры, достаточного заполнения для переполнения стека myFnи некоторых дополнительных данных, чтобы перезаписать адрес возврата, myFnчтобы он указывал на код, который он дал вам. Если это происходит, то, когда myFnобычно возвращал бы управление своему вызывающему, он вместо этого переходил к коду, предоставленному злоумышленником. Если вы пишете код на C (или C ++), который потенциально может быть подвержен ненадежным пользователям, вам необходимо понять этот вектор атаки, Вы должны понимать, почему переполнение буфера в стеке часто (но не всегда) легче использовать, чем в куче, и вы должны понимать, как распределяется память в куче (не слишком подробно, обязательно, но Идея о том, что у malloc()'ed области есть управляющие структуры, окружающие ее, может помочь понять, почему ваша программа падает в другой malloc()или в free()).

C предоставляет вам низкоуровневую информацию о том, как работает ваша машина, и дает вам более прямой контроль над вашей машиной, чем любой другой язык, отредактированный пользователем, который широко используется сегодня. С большой силой приходит большая ответственность - вам действительно нужно понимать эти детали низкого уровня, чтобы работать с C безопасно и эффективно.


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.