Коммутативность не имеет никакого отношения к "арифметике указателей". Коммутативен встроенный бинарный оператор + и коммутативен абсолютно всегда, безусловно и во всех контекстах.
Это не принципиально. Завязка на 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) происходит автоматическое преобразование типа "массив" к типу "указатель".
Это грубо не верно. И в С, и в С++ такое выражение порождает неопределенное поведение, а никакие не "13 или 14". Даже после введения более жестких правил sequencing в С++11, С++14 и С++17 это выражение все равно порождает неопределенное поведение в С++.
Оператор sizeof в языке C не обязательно обрабатывается в процессе компиляции. Если аргументом sizeof является VLA (Variable Length Array), то оператор sizeof будет вычисляться во время выполнения. Вот такое применение sizeof будет инкрементировать 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, где массивы действительно являлись указателями), а в том, что ни у кого не хватает смелости расширить список контекстов, в которых такого преобразования не делается. Нет никаких физических преград для того, чтобы включить "копирующие" контексты в список контекстов-исключений, и тем самым сделать массивы копируемыми. Но соображения обратной совместимости, понятное дело, мешают сильно.
Коммутативность не имеет никакого отношения к "арифметике указателей". Коммутативен встроенный бинарный оператор
+
и коммутативен абсолютно всегда, безусловно и во всех контекстах.Это не принципиально. Завязка на 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
В коде, написанном на С- и С++-подобных языках всенепременнейше рекомендуется писать открывающую фигурную скобку на отдельной строчке: это создает визуальное вертикальное разделение между предшествующим такой скобке кодом (зачастую: заголовок цикла,
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, где массивы действительно являлись указателями), а в том, что ни у кого не хватает смелости расширить список контекстов, в которых такого преобразования не делается. Нет никаких физических преград для того, чтобы включить "копирующие" контексты в список контекстов-исключений, и тем самым сделать массивы копируемыми. Но соображения обратной совместимости, понятное дело, мешают сильно.