Думаешь, ты знаешь Си?

в 12:43, , рубрики: C, c++, edisonsoftware, Блог компании Edison, задачки, Занимательные задачки, Программирование, разработка, тестирование
image

Многие программисты утверждают, что знают С. Ну что ж, у него самый известный синтаксис, он существует уже 44 года и он не захламлен непонятными функциями. Он прост!

Я имею ввиду, что просто утверждать, что вы знаете С. Вероятно вы изучили его в институте или по ходу дела, скорее всего у вас есть какой-то опыт в его использовании, наверное вы думаете, что знаете его вдоль и поперек, потому что там не много-то надо знать. Вообще-то много. С не так прост.

Если вы думаете что он прост — пройдите этот тест. В нем всего 5 вопросов. Каждый вопрос в принципе одинаковый: какое будет значение возврата?

Поддержка публикации — компания Edison, которая разрабатывает системы электронных архивов и документооборота, а так же интегрирует софт и хард для промышленных предприятий.

В каждом вопросе есть 4 варианта ответа из которых один и только один является верным.

1

struct S{
  int i;
  char c;
} s;

main(){
  return sizeof(*(&s));
}

А. 4
В. 5
С. 8
D. Я не знаю

2

main(){
  char a = 0;
  short int b = 0;
  return sizeof(b) == sizeof(a+b);
}

А. 0
В. 1
С. 2
D. Я не знаю

3

main(){
  char a = ‘ ‘ * 13;
  return a;
}

А. 416
В. 160
С. -96
D. Я не знаю

4

main()
{
  int i = 16;
  return (((((i >= i) << i) >> i) <= i));
}

А. 0
В. 1
С. 16
D. Я не знаю

5


main(){
  int i = 0;
  return i++ + ++i;
}

А. 1
В. 2
С. 3
D. Я не знаю

Вот и все, положите свои ручки. Ответы последуют сразу после музыкальной паузы

image
Большая месса в С миноре Вольфганга Амадеуса Моцарта. Да, Моцарт тоже писал на С.

Итак верные ответы

Думаешь, ты знаешь Си? - 3
Да, правильный ответ к каждому вопросу «Я не знаю».

Теперь давайте разберемся с каждым из них.

Первый в действительности о структуре отступов. C компилятор знает что хранение невыравненных данных в RAM может быть дорогостоящим, поэтому он выравнивает ваши данные за вас. Если у вас есть 5 байт данных в структуре, вероятнее всего он сделает из них 8. Или 16. Или 6. Или сколько он хочет. Существуют такие расширения как GCC атрибуты aligned и packed которые позволяют вам получить некоторый контроль над этим процессом, но они не стандартизированные. Сам по себе C не определяет атрибуты отступов и поэтому верный ответ «Я не знаю».

Второй вопрос о integer promotion. Логично предположить, что тип short int и выражение, где наибольший тип тоже short int будут одинаковыми. Но логичное не означает верное для С. Существует правило где каждое целое выражение продвигается до int. Вообще-то все еще более запутанно. Загляните в стандарт, вам понравится.

Но даже так, мы не сравниваем типы, мы сравниваем размеры. И единственная гарантия которую стандарт дает о размерах short int и int в том, что предшествующий не должен быть больше последующего. Они вполне могут быть равными. И поэтому верный ответ «Я не знаю».

Третий вопрос полностью о темных углах. Начиная с того, что ни переполнения integer ни наличие знака у типа char не определены стандартом. В первом случае у нас неопределенное поведение, во втором наличие знака зависит от конкретной реализации. Более того, размер типа char в битах не определен. Существовали платформы где он был по 6 бит (помните триграфы?) и существуют платформы где все пять целочисленных типов по 32 бита. Без уточнения всех этих деталей каждое предположение о результате невалидное, поэтому ответ будет «Я не знаю».

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

И поэтому снова верным ответом будет « Я не знаю».

И последний вопрос — классический. Ни порядок вычисления операндов для + ни даже порядок приоритета между операторами инкримента не определены, поэтому по существу каждая нетривиальная операция которая вовлекает i++ и ++i является ловушкой, так как они изменяют своего операнда. Все может работать как вы и ожидаете на одной платформе и легко может сломаться на другой. Или нет. Вот она проблема неопределенных вещей. Когда вы встречаете такое, верный ответ всегда будет « Я не знаю».

image
Большая месса в С миноре, написанная Вольфгангом Амадейсом Моцартом.

И на этом этапе я должен извиниться. Очевидно, что тест провокационный и может быть даже немного оскорбительный. Я приношу извинения если он вызвал какое-либо раздражение.

Дело в том, что я изучил С приблизительно в 1998 и на протяжении целых 15 лет думал, что я хорош в нем. Я выбрал этот язык в институте и реализовал некоторые успешные проекты на С на моей первой работе и даже тогда, когда я в основном работал на С++ я воспринимал его как чрезмерно раздутый С.

Поворотный момент настал в 2013 году, когда я участвовал в программировании критического для безопасности PLC. Это был исследовательский проект автоматизации на ядерной станции, где совершенно не принималась не полная спецификация. Я должен был осознать то, что хотя я знал многое о программировании на С, абсолютно бОльшая часть того что я знал было неверным. И это знание далось мне нелегко.

В конечном итоге мне пришлось научиться полагаться на стандарт вместо народной мудрости; доверять измерениям, а не предположениям, относиться к «вещам которые просто работают» скептически, — мне пришлось изучить подход технического проектирования. Это самое главное, а не какие-то конкретные WAT анекдоты.

Я надеюсь, что этот маленький тест поможет кому-то вроде меня из прошлого, узнать этот подход за 15 минут, а не 15 лет.

Перевод: Ольга Чернопицкая

Автор: Edison

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js