Подтвердить что ты не робот

Почему C имеет различие между → и.?

Хорошо, это не имеет никакого серьезного последствия, но это подталкивало меня к в то время как: есть ли причина различия между операторами -> и .?

Конечно, текущее правило состоит в том, что . действует на структуру, а -> действует на указатель на структуру (или объединение). Но вот как это работает на практике. Пусть s - структура, включающая элемент x, и пусть ps - указатель на структуру того же вида.

Если вы пишете

s->x

компилятор выдаст предупреждение на

Вы имели в виду s.x. Повторите попытку и перекомпилируйте.

Если вы пишете

ps.x

компилятор выдаст предупреждение на

Вы имели в виду ps- > x. Повторите попытку и перекомпилируйте.

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

Итак, вот гипотетическое предложение комитету по стандартам C1x (который никогда не будет рассмотрен, поскольку ISO находится на консервативной полосе):

Учитывая выражение lhs.rhs, если lhs является структурным или объединенным типом,     то выражение должно ссылаться на элемент lhs с именем rhs.     Если lhs имеет тип pointer-to-struct или -union, то это должно быть     интерпретируется как (* lhs).rhs.

Это, безусловно, спасло бы нас все время и облегчило бы людям изучать C [и я научил достаточно C, чтобы сказать с полномочиями, что учащиеся находят, что -> может быть запутанным или раздражающим.]

Там даже прецедент, где C делает несколько подобных вещей. Например, для целей реализации декларации функций всегда передаются в указатель на функцию, поэтому f(x,y) и (*f)(x,y) будут работать независимо от того, была ли объявлена ​​f как функция или указатель на функцию.

Итак, мой вопрос: что случилось с этим предложением? Можете ли вы придумать примеры, где будет фатальная двусмысленность между ps.x и s.x, или почему сохранение обязательного различия в противном случае полезно?

4b9b3361

Ответ 1

Хорошо, если вы действительно хотели ввести такую ​​функциональность в спецификацию языка C, то для того, чтобы сделать ее "смешаной" с остальной частью языка, логической задачей было бы расширить концепцию "распад на указатель" на типы структур. Вы сами сделали пример с функцией и указателем функции. Причина, по которой он работает, заключается в том, что тип функции в C распадается на тип указателя во всех контекстах, за исключением операторов sizeof и унарных &. (То же самое происходит с массивами, BTW.)

Итак, чтобы реализовать что-то похожее на то, что вы предлагаете, мы могли бы ввести понятие "распад struct-to-pointer", который будет работать точно так же, как и все другие "распады" в C (а именно, распад матрицы к указателю и распад функции-к-указателю) работают: когда в выражении используется структурный объект типа T, его тип немедленно распадается, чтобы набрать T* - указатель на начало объекта struct - кроме случаев, когда это операнд sizeof или унарный &. Как только такое правило распада вводится для структур, вы можете использовать оператор -> для доступа к элементам структуры, независимо от того, есть ли указатель на структуру или собственно структуру слева. Оператор . стал бы совершенно ненужным в этом случае (если только я чего-то не хватает), вы всегда будете использовать -> и только ->.

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

Но я бы сказал (согласен с тем, что сказал Чарльз), что потеря визуального различия между кодом, который работает с указателями на структуры и кодом, который работает с самими структурами, не совсем желателен.

P.S. Очевидным негативным следствием такого правила распада для структур было бы то, что, помимо нынешней армии новичков, самоотверженно полагающих, что "массивы являются просто постоянными указателями", у нас была бы армия новичков, самоотверженно полагающих, что "структурные объекты - это просто постоянные указатели", Часто задаваемые вопросы о массиве Chris Torek должны быть примерно в 1,5-2 раза больше для покрытия структур:)

Ответ 2

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

Однако мне нравится тот факт, что указатели на структуры и структуры обрабатываются по-разному.

Он дает некоторый контекст относительно операций и подсказок относительно того, что может быть дорогостоящим.

Рассмотрим этот фрагмент, представьте, что он находится в середине достаточно большой функции.

s.c = 99;
f(s);

assert(s.c == 99);

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

Если использование . с указателями на struct было разрешено, я бы ничего не знал об этом, и утверждение могло бы срабатывать, f может установить s.c (err s->c) на что-то еще.

Другим недостатком является то, что это уменьшит совместимость с С++. С++ позволяет -> перегружаться классами, чтобы классы могли быть "как" указатели. Важно, чтобы . и -> вели себя по-другому. "Новый" C-код, который использовал . с указателями на структуры, не был бы, вероятно, неприемлем, как код на С++.

Ответ 3

Ну, очевидно, нет никакой двусмысленности или предложение не может быть сделано. Единственная проблема заключается в том, что если вы видите:

p->x = 3;

вы знаете, что p - это указатель, но если вы разрешаете:

p.x = 3;

в этом случае, вы на самом деле не знаете, что потенциально может создать проблемы, особенно если вы позже произнесете этот указатель и используете неправильное количество уровней косвенности.

Ответ 4

Отличительной особенностью языка программирования C (в отличие от его относительного С++) является то, что модель затрат очень явная. Точка отличается от стрелки, потому что стрелка требует дополнительной ссылки на память, а C очень осторожно делает количество ссылок на память очевидным из исходного кода.

Ответ 5

Ну, наверняка могут быть случаи, когда у вас есть что-то сложное:

(*item)->elem

(который я имел в некоторых программах), и если вы написали что-то вроде

item.elem

что означает вышеизложенное, это может сбить с толку, является ли elem элементом элемента struct или элементом структуры, на который указывает элемент или элементом структуры, на который указывает элемент в списке, который указан с помощью элемента итератора и т.д. и т.д.

Итак, да, это делает вещи более ясными при использовании указателей на указатели на структуры, и .

Ответ 6

Да, это нормально, но это не то, что действительно нужно C

Не только это нормально, но и современный стиль. Java и Go оба используют только .. Поскольку все, что не вписывается в регистр, на каком-то уровне является ссылкой, различие между вещью и указателем на вещь определенно немного произвольно, по крайней мере, пока вы не получите функциональные вызовы.

Первый эволюционный шаг состоял в том, чтобы сделать пострефикс оператора разыменования, что-то dmr, как только подразумевалось, что он в какой-то момент предпочитает, Паскаль делает это, поэтому он имеет p^.field. Единственная причина, по которой существует оператор ->, состоит в том, что он должен иметь тип (*p).field или p[0].field.

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

Я утверждал, что использование () для вызовов функций и [] для подстроки массива неверно. Почему бы не позволить различным реализациям экспортировать разные абстракции?

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

На самом деле C действительно нуждается в том, чтобы никогда не создавать более безопасные коды. Я не против работать на C, но руководителям проектов не нравится, когда их надежность определяется их худший парень, и, возможно, что C действительно нуждается в безопасном диалекте, что-то как Cyclone, или возможно что-то вроде Go.

Ответ 7

Во всяком случае, текущий синтаксис позволяет читателям кода знать, работает ли код с указателем или фактическим объектом. Кто-то, кто не знает код заранее, понимает это лучше.