All streams
Search
Write a publication
Pull to refresh
37
0
Send message

Коммутативность не имеет никакого отношения к "арифметике указателей". Коммутативен встроенный бинарный оператор + и коммутативен абсолютно всегда, безусловно и во всех контекстах.

Это не принципиально. Завязка на character set в решении таких задач — это совершенно неинтересный читинг. А тут еще 90% приведенных "решений" — унылое повторение снова, снова и снова одного и того же приема с *"строка", к тому же завязанного на character set.

На С++ все даже хуже, ибо в С++ символьная константа имеет тип char, а не int. И это значит, что в С++ все ваши символьные константы будет подвергаться integral promotions, которые, в зависимости от платформы, могут превратить ее в int или в unsigned int. Вариант с unsigned int — целый ящик Пандоры самостоятельных проблем. (Хотя аналогичные проблемы с integral promotions присутствуют в этом коде и с точки зрения С).

Запросто!


На "во-первых" аргументы очевидны: большинство вариантов завязаны на свойство платфоременно-зависимого character set. Вот и все. К тому же фактически способов что-то сделать у вас от силы три. И один из них — применение * к строковому литералу — раздут в огромное число вариантов. Зачем было делать искусственное и скучное раздувание этих способов в такое количество уныло повторяющихся вариантов — не ясно. Это же сразу бросается в глаза.


Найти остроумные решения, которые бы работали на настоящем стандартном С — вот это действительно интересная задача, потому что в ней заключается challenge. А ваши чисто косметические выверты на фактически готовеньком результате (т.е. на конкретных значениях character constants) — примитивная пустышка/профанация для студенток-первокурсниц.


На "во-вторых" аргументы тоже несложны: хорошо известно, что ideone занимается наглой пост-фильтрацией диагностических сообщений компилятора. Не видя стандартных диагностических сообщений компилятора рядовой пользователь не сможет судить о корректности кода. Ваш код грубо ошибочен, но тем не менее проглатывается ideone — вескость этого аргумента переоценить невозможно.


Например, для использования true и false обязательно требуется включение <stdbool.h>. Для использования compl и xor обязательно требуется включение <iso646.h>. У вас же ideone в режиме С (!) проглотил это все даже не поперхнувшись. Именно по таким причинам в темах по языку С не принято оскорблять присутствующих ссылками на потешные глюкала типа ideone. Возмите в привычку пользоваться общепризнанными стандартами типа coliru. Какой бы вы ресурс не использовали, контроль над командной строкой компилятора — обязателен.


P.S. Ой, только что обратил внимание! Вы вообще в С++ это все компилировали! Так зачем же вы нам тогда баки забиваете какими то сказками про "практику программирования на C"?

Во-первых, ваши решения написаны не на С, а на GCC, да и те платформеннозависимы. Такие задачи интереснее решать именно на стандартном С. Ваши решения в большинстве своем к С относятся мало или вообще никак.


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

Правила strict aliasing пристутвует в стандарте С++ с начала времен. А "проблемы про strict aliasing там нет" лишь означает, что оптимизаций, основанных на использовании правил strict aliasing в MSVC пока не реализовали. Сегодня не реализовали — завтра реализуют.

Как правильно заметил mayorovp, компилятор вправе игнорировать информационную зависимость между n[] и nAddress, т.е. полагать, что эти значения никак между собой не связаны и никак друг на друга не влияют. Манипуляции со значением n[] могут быть свободно перенесены вверх по коду — туда, где nAddress еще не получил правильного значения.

В С вы что-то не то проверяли. Выражение ошибочно, но потому, что -- требует lvalue, а ++ возвращает rvalue. Диагностическое сообщение будет другим. (Кстати, по сути совпадающее с джавовским.)

Не совсем понял, что именно вы хотели сказать первой частью вашего комментария. Там все правильно, но к чему это здесь и как это отвечает на мой комментарий?


Что касается второй части — нет, так делать нельзя. Это грубое нарушение правил strict aliasing. Работать может только чисто на везении.

Плохо проверяли. В языке С никогда не было никакого встроенного bitand. Эти слова в языке С всегда были макросами из <iso646.h>. Никуда они не делись — подключайте <iso646.h> и будет вам ваш bitand.

Двумерный массив — это массив массивов. Поэтому при указании только одного индекса возвращается не "адрес", а массив — lvalue типа uint64 [3]. А уж "адресом" он становится позже, благодаря тому, что в вашем контексте (аргумент memcmp) происходит автоматическое преобразование типа "массив" к типу "указатель".

В языках С и С++ sizeof(char) всегда по определению равно 1.

Это грубо не верно. И в С, и в С++ такое выражение порождает неопределенное поведение, а никакие не "13 или 14". Даже после введения более жестких правил sequencing в С++11, С++14 и С++17 это выражение все равно порождает неопределенное поведение в С++.

Оператор sizeof в языке C не обязательно обрабатывается в процессе компиляции. Если аргументом sizeof является VLA (Variable Length Array), то оператор sizeof будет вычисляться во время выполнения. Вот такое применение sizeof будет инкрементировать x


  int x = 0;
  sizeof(int[++x]);
  printf("%d\n", x);

В коде, написанном на С- и С++-подобных языках всенепременнейше рекомендуется писать открывающую фигурную скобку на отдельной строчке: это создает визуальное вертикальное разделение между предшествующим такой скобке кодом (зачастую: заголовок цикла, if с условием и т.п.) и собственно телом compound statement. Наличие такого вертикального разделения астрономически повышает читаемость кода.


Вопрос "вертикального размазывания кода" уже давно не актуален. Код должен содержать огромное количество грамотно расставленного вертикального спейсинга. Преимущества в удобочитаемости кода легко затмевают потери в количестве умещающихся на экране строк.


За "египетские скобки" в современном коде надо бить по рукам так же, как и за явное приведение результата malloc в C.

Это так, но последнее время и С и С++ ведут себя довольно смело с депрекацией фич, которые могут создать проблемы с обратной совместимостью. В С++ чего стоят одни только депрекации dynamic exception specification и неявного объявления функций копирования в классах.

Первая часть — неверно. Это никогда не "означало массив из трех элементов", как вы ошибочно полагаете.


В С89/90 и С++ размер массива в объявлении массива должен задаваться константным выражением. Но константное выражение в этих языках грамматически не может содержать оператора "запятая" на верхнем уровне. Поэтому последовательность int x[2, 3] является грамматически неверной, т.е. не вообще в принципе никак не распарсиваемой в этих языках.


Единственным грамматически верным способом протащить оператор "запятая" в константное выражение является использование дополнительных круглых скобок: int x[(2, 3)]. Однако в С и pre-C++11 С++ тут дополнительно вступают в силу уже явные (неграмматические) ограничения, дополнительно оговоренные в тексте стандарта: константным выражениям открытым текстом запрещено использовать оператор "запятая".


В post-C99 С размер локального массива уже не обязан быть константным выражением, но грамматика по прежнему сформулирована так, что int x[2, 3] не является распарсиваемой последовательностью. Поэтому в С99 разрешается только int x[(2, 3)].


В post-C++11 C++ разрешается использование оператора "запятая" в константных выражениях, но структура грамматики оставлена прежней, то есть в С++11 int x[2, 3] по прежнему не является распарсиваемой последовательностью. Поэтому в С++11 разрешается только int x[(2, 3)].


Вторая часть — верно. Действительно x[1,0] — это обращение к нулевому элементу и да, тут вы правы: оператор "запятая" мешает в контексте доступа. Тут бы потребовалось волевое решение: модификация грамматики по образу и подобию грамматики объявления (как я описал выше): грамматически запретить использование оператора "запятая" на верхнем уровне выражения. В принципе, возможно это стоило бы сделать вообще везде, т.е. разрешить использование оператора "запятая" только внутри скобок.

Каким образом фича языка может "мешать" — ума не приложу...

"Слышал звон да не знал где он". Ничего подобного в С++11 нет и никогда не было. С и С++ настолько фундаментально различные языки, что никакого "включения" между ними нет и быть не может.


By reference в С++ включается только интерфейсная спецификация стандартной билиотеки, да и то с массой оговорок.

"… имя массива эквивалентно указателю на первый элемент массива..." — поле такой белиберды дальше можно не читать. Написана ерунда.


Автоматическое приведение объекта типа "массив" к значению типа "указатель" делается в С не безусловно, а лишь в наборе четко оговоренных контекстов. Например, в контекстах операторов & и sizeof такого приведения не делается.


Отсюда сразу становится ясно, что дело тот не в существовании такого приведения (которое, кстати, не является "синтаксической оптимизацией", а растет еще из B и BCPL, где массивы действительно являлись указателями), а в том, что ни у кого не хватает смелости расширить список контекстов, в которых такого преобразования не делается. Нет никаких физических преград для того, чтобы включить "копирующие" контексты в список контекстов-исключений, и тем самым сделать массивы копируемыми. Но соображения обратной совместимости, понятное дело, мешают сильно.

Information

Rating
Does not participate
Registered
Activity