Эбботт: В чем смысл?

Костелло: Я понимаю суть, но куда она указывает?!?

Эбботт: Какой компилятор вы используете?

Костелло: Не удивляйтесь, меня зовут не компилятор, и я иду, а не бегу. Похоже, я тороплюсь?

Жаль, что Эббота и Костелло уже нет в живых. Я уверен, что они сделали бы достойное обновление скетча «Кто первый», который затмит мой.

У нас больше нет Эбботта и Костелло, чтобы развлекать нас. Но это нормально. Мы, программисты, довольно веселая компания, и компьютеры умеют нас развлекать.

Как программист, вы могли бы задуматься над вопросом: В чем смысл? быть вне сферы действия. Но немного другой вопрос, который определенно актуален для программиста на C: На что указывает этот указатель? Рассмотрим пример:

Если вы привыкли смотреть на C-код, то могли заметить нечто странное. Первый оператор printf кажется вполне нормальным. Он выводит адрес памяти первого элемента двухэлементного массива символов. Но что делает следующий оператор printf??? Сколько элементов в массиве с именем 0??? 0 не является объявленной переменной, и переменные в любом случае не могут иметь номер в качестве первого символа своего имени. Что будет делать этот код? Будет ли он даже скомпилирован? И если да, то какой будет результат? Давайте бросим его компилятору и посмотрим, что произойдет…

Хорошо, но что будет на выходе после выполнения? Прежде чем мы доберемся до этого…

Как выглядеть умным, не отвечая на вопрос

Когда ваш друг задает вам вопрос о каком-то малоизвестном уголке языка C, ответьте на вопрос другим вопросом, например: «Какой компилятор вы будете использовать для компиляции этого кода, о котором вы говорите? Мне нужно знать компилятор, который вы используете, чтобы дать окончательный ответ». Этот ответ должен дать вам некоторую передышку, если вы не в курсе C arcana.

Мало ли они знают…

… что вы настойчивы и на самом деле *будете* устанавливать другой компилятор C, чтобы быть знающим программистом. Какой компилятор поставить? Что ж, gcc и clang — два наиболее часто используемых компилятора, и они должны быть ими какое-то время (с точки зрения 2017 года). Итак, уже увидев, как gcc передает код нашего примера, давайте посмотрим, что clang v.3.8.0 может сказать о нашем странном синтаксисе:

clang, похоже, тоже не возражает. Что эти компиляторы знают такого, чего не знаем мы?

Для обзора:

Мы состряпали скрипт с каким-то странным синтаксисом (см. выше). В частности, этот фрагмент: &0[c] Кажется, он просит компилятор C сослаться на массив, который не имеет допустимого имени переменной. Индекс массива внутри квадратных скобок — это указатель c, указывающий на место в верхней части памяти на моем обычном ноутбуке с 64-битной операционной системой. Мы знаем, что любой результат, который мы получим от 0[c], будет разыменован амперсандом: & даст нам не значение, хранящееся в 0[c], а местоположение в памяти 0[c].

Вот вывод (скомпилированный gcc v.4.8.4 в 64-битной системе Linux):

Что нам говорит этот вывод?

Важно отметить, что мы распечатали местоположение элемента массива двух разных массивов, используя: &a[0] и &0[a]. То, что мы видим выше, когда мы изучаем вывод нашего сценария, заключается в том, что две области памяти являются одними и теми же. Почему это должно быть? Вот вывод, к которому я вынужден прийти: я мог бы ввести любое число для имени массива, и до тех пор, пока оно удовлетворяет этому условию:

Самое низкое доступное место в памяти ≤ число, связанное с именем переменной массива ≤ максимальное место в памяти.

Кроме того, число, связанное с именем переменной (например, a), можно заменить простым числовым значением (например, 0). Разумно ли жестко запрограммировать числовую ячейку памяти вместо того, чтобы позволять C определять, где в памяти хранить ваши переменные? Как правило, нет. Но возможно ли это? Да, доказательство прямо здесь, и оно даже работает на двух разных компиляторах.

И это дает мне что?

Экспериментируя с кодом, мы получаем представление о внутренней работе языка Си, реализованной компилятором. И мы на шаг ближе к самому возвышенному искусству: созданию и пониманию запутанного кода!

Спасибо моей однокурснице Джулии Ли, которая написала и протестировала код для этой записи в блоге!

Кроме того, вам следует отдать должное, если вы измените и протестируете пример сценария. Что произойдет, если указатель указывает не на char, а на что-то другое?

Загляните в мою учетную запись на github здесь и подпишитесь на меня в твиттере!