Думаєш ти знаєш Сі?

image
Багато програмісти стверджують, що знають С. Ну що ж, у нього найвідоміший синтаксис, він існує вже 44 роки і він не захаращений незрозумілими функціями. Він простий!

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

Якщо ви думаєте що він простий — пройдіть цей тест. У ньому всього 5 питань. Кожне питання в принципі однаковий: яке значення повернення?

У кожному питанні є 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
Велика меса З мінорі Вольфганга Амадеуса Моцарта. Так, Моцарт теж писав на С.

Отже вірні відповіді
Так, правильна відповідь до кожного питання «Я не знаю».

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

Перший насправді про структуру відступів. 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 років.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.