Мы все много раз слышали, что говорит Страуструп. Ответ: нет, это его заявления из категории "это было давно и неправда". Страуструп часто несет чушь по вопросам практического программирования. Не первый раз его ловят на подобных заблуждениях.
На самом деле все с точностью до наоборот: НЕ пользуйтесь знаковыми типами без явной на то необходимости. Подавляющее большинство целочисленных переменных в вашей программе должно быть беззнаковыми.
Неясно, зачем надо было создавать сбивающий с толка заголовок. Значение выражения -3 / 3u * 3 во всех компиляторах С и С++ с 32-битным int без исключения равно 4294967292 . Без вариантов. Конкретное значение зависит от ширины типа unsigned intна данной платформе, но никогда и нигде оно не будет отрицательным. Тип выражения -3 / 3u * 3 - всегда unsigned int, без вариантов.
Поэтому о каком -4 разглагольствует автор поста - не ясно. Нет, никакого -4 тут нет и быть не может. Если же вам захотелось рассказать нам, что 4294967292, насильно приведенное к типу int дает -4на платформе с дополнительным кодом... ОК, но ничего заслуживающего отдельного поста в этом нет.
Зачем нужно было устраивать "исследование" того, что открытым тестом написано в спецификации языка - тоже не ясно. Более того, никаких ассемблерных листингов в таких исследования не допускается, ибо они вторичны по отношению к стандарту языка.
А я узнал, что существительное "длина" может писаться как с одной, так и с двумя "н". По-видимому в зависимости от того, насколько длинна эта длина. Интересно, если ли версия с тремя "н"?
… Те далекие времена, когда в Гарварде еще занимались наукой и образованием, а не нынешней "подготовкой будущих лидеров мира". Те далекие времена, когда звание выпускника Гарварда еще не воспринималось как оскорбление ...
Во-первых, в контекстах с выраженной булевской семаниткой, явное намного хуже неявного.
Во-вторых, почему результат предыдущего != 0 — неявен, в результат == false вдруг явен? Где логика?
И, самое главное, в третьих, если со скрежетом зубов еще можно пропустить == true, то == false — это совершенно нечитаемо. Скрытая в == false неявная инверсия полностью убивает читаемость кода.
Это совершенно не важно, что получается в результате неопределенного поведения и как ведут себя разные компиляторы, потому что программа с неопределенным поведением не является корректной программой на языках С или С++. Анализировать поведение вашего кода и строить из него какие-то выводы — это по сути то же самое, что анализировать содержимое неинициализированной переменной. С точки зрения языка С++ в ваших экспериментах фактически нет никакой программы, а есть просто "мусор", который остался после компиляции (компилятор просто забыл или не сумел его почистить). И вы зачем-то пытаетесь не только запускать этот "мусор" (!), но еще и разглядывать результаты (!!). Зачем?
Ключевым моментом здесь является то, компиляторы С и С++ имеют право транслировать код исходя из предположения, что неопределенное поведение никогда не возникает (напр. компилятор С или С++ имеет право заменить целое d / d на константу 1 даже если есть вероятность того, что d окажется равным 0). Именно в этом заключается суть утверждения "в С++ const верхнего уровня является гарантией того, что объект не может меняться"
Нет, это не "не так". const_cast в С++ предназначен для вполне конкретной цели — снятие константности с пути доступа к объекту, т.е. константности первого или более глубоких уровней вложенности. В С++ не существует средств снятия константности нулевого (верхнего) уровня, т.е. константности самого объекта и const_cast вам ничем здесь не поможет.
В любом случае, попытки модификации константного объекта через неконстантный путь доступа (как бы вы его ни получили) НЕ модифицируют объект, а приводят в неопределенному поведению. Так что, еще раз: в С++ const верхнего уровня является гарантией того, что объект не может меняться.
Еще раз: вы сделали утверждение, что "const — это не гарантия того, что объект не может меняться". Я вас поправляю: const верхнего уровня (т.е. примененный непосредственно к объекту, а не к пути доступа) является гарантией того, что объект не может меняться.
Да, именно словоблудие! Причем на словоблудие это я/мы им указывали не раз и по своей инициативе, и в процессе оплаченных Интелом (!) же ревью их документации, но воз, как говорится, и ныне там. Но основная проблема, боюсь, не в интеловской документации, а лично в вашем неумении понимать прочитанное.
Про возвращаемое значение — совершенно неверно! Тот факт, что возвращаемое значение является rvalue абсолютно ничего не меняет. Зачем вы это повторяете? Еще раз: в языке С++ для rvalue класс-типов cv-квалификация совершенно полноценно применима и всегда была применима (!), как я уже ясно сказал выше. Вы же почему-то продолжаете твердить, что она якобы "тут применена не может". Что за чушь? Попробуйте, в конце концов, сами
Замечаете разницу? То-то. А далее уже самостоятельно: вперед изучать свойства cv-квалификации в С++.
Что касается параметров, вы вдруг полезли рассказывать про эквивалентность прототипов. Это так, но к чему вдруг здесь прототипы? Прототип описывает внешнюю спецификацию функции и она действительно не меняется от cv-квалификации параметров. Но к делу это вообще никак не относится. Еще раз, как уже было ясно сказано выше: cv-квалификация параметра имеет абсолютно явный и однозначный эффект по отношению к семантике этого параметра внутри определения функции. Прототипы к этому никакого отношения не имеют. (P.S. В С++ нет "прототипов").
Ну то есть похоже что библиотека NemaStepper является простейшей тонкой оболочкой для реализации типичной ардуиновской кооперативной многозадачности для управления степперами.
Это нормально, но меня удивила ваша фраза "Когда я искал решение моей проблемы, единственной подходящей библиотекой оказалась она". Это звучит примерно как "я искал, как увеличить переменную на 1, и перепробовав несколько, нашел только библиотеку Increment". У всех естественно возникнет вопрос: а чем вам простое ++i не подошло? Вот так же и здесь: зачем было искать библиотеку для кооперативного управления степпер-моторами (особенно если это потребовало усилий), когда это, мягко говоря, элементарное действие?
У вас наблюдается все та же путаница между двумя принципиально разными типами константности: константностью самого объекта и константностью пути доступа к объекту.
Константность объекта — это в С и С++ всегда гарантия того, что объект не может меняться (кроме mutable членов объектов классов).
Путаница вызвана в первую очередь незнанием терминологии.
В языке С есть термин "константа". Константами в С называются буквальные значения (1, 'a', 3.14) и элементы enum. Далее все покрывается термином "константное выражение". const-объекты в C "константами" не называются вообще и константных выражений не формируют.
В языке С++ термина "константа" применяется только к элементам enum. Буквальные значения называются "литералами". Все остальное выражается через термин "константное выражение". Характерно то, что в С++, в отличие от С, const-объекты формируют константные выражения.
Цитата из Интел тут ни к чему — Интел и их документация не славятся (мягко говоря) хорошим знанием языка С++. Вот и та цитата, которую вы здесь привели — безграмотная чушь. Эту чушь еще можно было худо-бедно подогнать под стандарт в рамках старинного С++98, но сегодня эта безграмотная чушь — безнадежна.
Цитата из стандарта языка, которую вы привели, описывает процесс формирования типа функции для целей overloading. Ни больше не меньше. Это совершено узкая, изолированная и посторонняя тема, не имеющая никакого отношения к рассматриваемому вопросу. К чему вы здесь ее привели?
В общем же ни о каком "ignored" для квалификаторов параметров и возвращаемого значения в С++ речи быть не может — они ни в коем случае не ignored (!).
Оба утверждения — не верны и являются популярной "пионэрской твердилкой".
Константность параметров, как вы сами сказали, влияет на семантику параметра в теле функции. В частности, такая константность активно и широко используется в coding standards, которые запрещают менять значения параметров внутри функции.
Константность возвращаемого значения действительно бессмысленна лишь для скалярных типов. Как только возвращаемое значение становится класс-типом эта константность тоже начинает влиять на семантику.
Я предлагаю рассматривать чисто теоретические соображения о том, какие оптимизации возможны, а какие — нет в рамках стандартной семантики языков С и С++. Если оптимизация теоретически возможна в рамках данного языка, то ее практическая реализация является лишь вопросом времени. То, что какая-то оптимизация еще не реализована неким компилятором, ничего не значит.
Не забывайте, что оптимизации в современных компиляторах С/С++ реализуются не на основе некоего "суперумного самообучающегося искусственного интеллекта", а на основе банальных механизмов pattern matching. Что будет и что не будет оптимизировать компилятор зависит только от того, какой набор оптимизационных паттернов в него уже успел вбить некий условный Вася Пупкин (в промежутках между сдачами сессий), и какой набор паттернов он НЕ успел вбить (в том числе потому, что бумажка с описанием соответствующего паттерна завалилась за шкаф).
Разглядывая сгенерированный компиляторами код вы фактически разглядываете последствия Васиного рабочего графика, Васиного энтузиазма или Васиной лени. Не надо на основе этого делать выводы об эффективности тех или иных конструкций языка. Особенно если учесть что репутация GCC сегодня лежит ниже плинтуса во многом из-за огромного баклога на фиксинг багов и реализацию критически необходимых фич.
Во-первых, const, разумеется, "ускоряет" код в тех ситуациях, когда он применяется к самому объекту, а не к "пути доступа" к объекту. Это прекрасно видно во всем, включая сгенерированный компилятором код. В применении же к путям доступа const действительно является лишь синтаксическим сахаром. Для оптимизации кода в таких ситуациях компилятору нужно знать полную картину aliasing, а const в этом никак не помогает. Для этого служит restrict.
Во-вторых, разглядывать для этих целей код, сгенерированный какими-то компиляторами — бессмысленно, особенно когда речь идет о GCC. GCC — отстал, крив и пионерск. Сегодня он не умеет что-то оптимизировать, но завтра — научится.
Это верно. Но во некоторых случаях это выливается в неприятный удар по производительности кода у ничего не подозревающего автора. Что-то вроде
char buffer[1024] = { [0] = '?' };
В тех случаях, когда производительность критична, а полная инициализация нулями не требуется, бывает разумнее прибегнуть к объявлению без инициализатора и последующему выборочному присваиванию.
На некоторых платформах с ограниченными ресурсами такая инициализация также может быть нежелательна из-за того, что "образ" всей инициализированной структуры попадает в сегмент инициализированных данных, тем самым раздувая размер этого сегмента. Объявление без инициализатора и с последующим выборочным присваиванием свободно от этого недостатка (по какой-то причине мейнстримовые компиляторы не делают такой оптимизации).
Мы все много раз слышали, что говорит Страуструп. Ответ: нет, это его заявления из категории "это было давно и неправда". Страуструп часто несет чушь по вопросам практического программирования. Не первый раз его ловят на подобных заблуждениях.
На самом деле все с точностью до наоборот: НЕ пользуйтесь знаковыми типами без явной на то необходимости. Подавляющее большинство целочисленных переменных в вашей программе должно быть беззнаковыми.
Неясно, зачем надо было создавать сбивающий с толка заголовок. Значение выражения
-3 / 3u * 3
во всех компиляторах С и С++ с 32-битнымint
без исключения равно4294967292
. Без вариантов. Конкретное значение зависит от ширины типаunsigned int
на данной платформе, но никогда и нигде оно не будет отрицательным. Тип выражения-3 / 3u * 3
- всегдаunsigned int
, без вариантов.Поэтому о каком
-4
разглагольствует автор поста - не ясно. Нет, никакого-4
тут нет и быть не может. Если же вам захотелось рассказать нам, что4294967292
, насильно приведенное к типуint
дает-4
на платформе с дополнительным кодом... ОК, но ничего заслуживающего отдельного поста в этом нет.Зачем нужно было устраивать "исследование" того, что открытым тестом написано в спецификации языка - тоже не ясно. Более того, никаких ассемблерных листингов в таких исследования не допускается, ибо они вторичны по отношению к стандарту языка.
А я узнал, что существительное "длина" может писаться как с одной, так и с двумя "н". По-видимому в зависимости от того, насколько длинна эта длина. Интересно, если ли версия с тремя "н"?
… Те далекие времена, когда в Гарварде еще занимались наукой и образованием, а не нынешней "подготовкой будущих лидеров мира". Те далекие времена, когда звание выпускника Гарварда еще не воспринималось как оскорбление ...
"Вот, например, такой код абсолютно валиден для C:..."
Нет, он не валиден для C. Язык С в вашем примере не будет знать, что такое
X
.Нет.
Во-первых, в контекстах с выраженной булевской семаниткой, явное намного хуже неявного.
Во-вторых, почему результат предыдущего
!= 0
— неявен, в результат== false
вдруг явен? Где логика?И, самое главное, в третьих, если со скрежетом зубов еще можно пропустить
== true
, то== false
— это совершенно нечитаемо. Скрытая в== false
неявная инверсия полностью убивает читаемость кода.Что это за магическая константа 8?
(А, вижу, уже заметили.)
В l298n есть много неэффективностей. Но не ясно при чем здесь биполярные двигатели. l298n прекрасно поддерживает биполярные двигатели.
Это совершенно не важно, что получается в результате неопределенного поведения и как ведут себя разные компиляторы, потому что программа с неопределенным поведением не является корректной программой на языках С или С++. Анализировать поведение вашего кода и строить из него какие-то выводы — это по сути то же самое, что анализировать содержимое неинициализированной переменной. С точки зрения языка С++ в ваших экспериментах фактически нет никакой программы, а есть просто "мусор", который остался после компиляции (компилятор просто забыл или не сумел его почистить). И вы зачем-то пытаетесь не только запускать этот "мусор" (!), но еще и разглядывать результаты (!!). Зачем?
Ключевым моментом здесь является то, компиляторы С и С++ имеют право транслировать код исходя из предположения, что неопределенное поведение никогда не возникает (напр. компилятор С или С++ имеет право заменить целое
d / d
на константу1
даже если есть вероятность того, чтоd
окажется равным0
). Именно в этом заключается суть утверждения "в С++const
верхнего уровня является гарантией того, что объект не может меняться"Нет, это не "не так".
const_cast
в С++ предназначен для вполне конкретной цели — снятие константности с пути доступа к объекту, т.е. константности первого или более глубоких уровней вложенности. В С++ не существует средств снятия константности нулевого (верхнего) уровня, т.е. константности самого объекта иconst_cast
вам ничем здесь не поможет.В любом случае, попытки модификации константного объекта через неконстантный путь доступа (как бы вы его ни получили) НЕ модифицируют объект, а приводят в неопределенному поведению. Так что, еще раз: в С++
const
верхнего уровня является гарантией того, что объект не может меняться.Прекрасно, но к чему это здесь?
Еще раз: вы сделали утверждение, что "const — это не гарантия того, что объект не может меняться". Я вас поправляю:
const
верхнего уровня (т.е. примененный непосредственно к объекту, а не к пути доступа) является гарантией того, что объект не может меняться.Ни больше, ни меньше.
Да, именно словоблудие! Причем на словоблудие это я/мы им указывали не раз и по своей инициативе, и в процессе оплаченных Интелом (!) же ревью их документации, но воз, как говорится, и ныне там. Но основная проблема, боюсь, не в интеловской документации, а лично в вашем неумении понимать прочитанное.
Про возвращаемое значение — совершенно неверно! Тот факт, что возвращаемое значение является rvalue абсолютно ничего не меняет. Зачем вы это повторяете? Еще раз: в языке С++ для rvalue класс-типов cv-квалификация совершенно полноценно применима и всегда была применима (!), как я уже ясно сказал выше. Вы же почему-то продолжаете твердить, что она якобы "тут применена не может". Что за чушь? Попробуйте, в конце концов, сами
Замечаете разницу? То-то. А далее уже самостоятельно: вперед изучать свойства cv-квалификации в С++.
Что касается параметров, вы вдруг полезли рассказывать про эквивалентность прототипов. Это так, но к чему вдруг здесь прототипы? Прототип описывает внешнюю спецификацию функции и она действительно не меняется от cv-квалификации параметров. Но к делу это вообще никак не относится. Еще раз, как уже было ясно сказано выше: cv-квалификация параметра имеет абсолютно явный и однозначный эффект по отношению к семантике этого параметра внутри определения функции. Прототипы к этому никакого отношения не имеют. (P.S. В С++ нет "прототипов").
Ну то есть похоже что библиотека NemaStepper является простейшей тонкой оболочкой для реализации типичной ардуиновской кооперативной многозадачности для управления степперами.
Это нормально, но меня удивила ваша фраза "Когда я искал решение моей проблемы, единственной подходящей библиотекой оказалась она". Это звучит примерно как "я искал, как увеличить переменную на 1, и перепробовав несколько, нашел только библиотеку Increment". У всех естественно возникнет вопрос: а чем вам простое
++i
не подошло? Вот так же и здесь: зачем было искать библиотеку для кооперативного управления степпер-моторами (особенно если это потребовало усилий), когда это, мягко говоря, элементарное действие?У вас наблюдается все та же путаница между двумя принципиально разными типами константности: константностью самого объекта и константностью пути доступа к объекту.
Константность объекта — это в С и С++ всегда гарантия того, что объект не может меняться (кроме
mutable
членов объектов классов).Путаница вызвана в первую очередь незнанием терминологии.
В языке С есть термин "константа". Константами в С называются буквальные значения (
1
,'a'
,3.14
) и элементы enum. Далее все покрывается термином "константное выражение".const
-объекты в C "константами" не называются вообще и константных выражений не формируют.В языке С++ термина "константа" применяется только к элементам enum. Буквальные значения называются "литералами". Все остальное выражается через термин "константное выражение". Характерно то, что в С++, в отличие от С,
const
-объекты формируют константные выражения.Цитата из Интел тут ни к чему — Интел и их документация не славятся (мягко говоря) хорошим знанием языка С++. Вот и та цитата, которую вы здесь привели — безграмотная чушь. Эту чушь еще можно было худо-бедно подогнать под стандарт в рамках старинного С++98, но сегодня эта безграмотная чушь — безнадежна.
Цитата из стандарта языка, которую вы привели, описывает процесс формирования типа функции для целей overloading. Ни больше не меньше. Это совершено узкая, изолированная и посторонняя тема, не имеющая никакого отношения к рассматриваемому вопросу. К чему вы здесь ее привели?
В общем же ни о каком "ignored" для квалификаторов параметров и возвращаемого значения в С++ речи быть не может — они ни в коем случае не ignored (!).
Оба утверждения — не верны и являются популярной "пионэрской твердилкой".
Константность параметров, как вы сами сказали, влияет на семантику параметра в теле функции. В частности, такая константность активно и широко используется в coding standards, которые запрещают менять значения параметров внутри функции.
Константность возвращаемого значения действительно бессмысленна лишь для скалярных типов. Как только возвращаемое значение становится класс-типом эта константность тоже начинает влиять на семантику.
Я предлагаю рассматривать чисто теоретические соображения о том, какие оптимизации возможны, а какие — нет в рамках стандартной семантики языков С и С++. Если оптимизация теоретически возможна в рамках данного языка, то ее практическая реализация является лишь вопросом времени. То, что какая-то оптимизация еще не реализована неким компилятором, ничего не значит.
Не забывайте, что оптимизации в современных компиляторах С/С++ реализуются не на основе некоего "суперумного самообучающегося искусственного интеллекта", а на основе банальных механизмов pattern matching. Что будет и что не будет оптимизировать компилятор зависит только от того, какой набор оптимизационных паттернов в него уже успел вбить некий условный Вася Пупкин (в промежутках между сдачами сессий), и какой набор паттернов он НЕ успел вбить (в том числе потому, что бумажка с описанием соответствующего паттерна завалилась за шкаф).
Разглядывая сгенерированный компиляторами код вы фактически разглядываете последствия Васиного рабочего графика, Васиного энтузиазма или Васиной лени. Не надо на основе этого делать выводы об эффективности тех или иных конструкций языка. Особенно если учесть что репутация GCC сегодня лежит ниже плинтуса во многом из-за огромного баклога на фиксинг багов и реализацию критически необходимых фич.
Какое-то очередное "открытие Америки".
Во-первых,
const
, разумеется, "ускоряет" код в тех ситуациях, когда он применяется к самому объекту, а не к "пути доступа" к объекту. Это прекрасно видно во всем, включая сгенерированный компилятором код. В применении же к путям доступаconst
действительно является лишь синтаксическим сахаром. Для оптимизации кода в таких ситуациях компилятору нужно знать полную картину aliasing, аconst
в этом никак не помогает. Для этого служитrestrict
.Во-вторых, разглядывать для этих целей код, сгенерированный какими-то компиляторами — бессмысленно, особенно когда речь идет о GCC. GCC — отстал, крив и пионерск. Сегодня он не умеет что-то оптимизировать, но завтра — научится.
Это верно. Но во некоторых случаях это выливается в неприятный удар по производительности кода у ничего не подозревающего автора. Что-то вроде
В тех случаях, когда производительность критична, а полная инициализация нулями не требуется, бывает разумнее прибегнуть к объявлению без инициализатора и последующему выборочному присваиванию.
На некоторых платформах с ограниченными ресурсами такая инициализация также может быть нежелательна из-за того, что "образ" всей инициализированной структуры попадает в сегмент инициализированных данных, тем самым раздувая размер этого сегмента. Объявление без инициализатора и с последующим выборочным присваиванием свободно от этого недостатка (по какой-то причине мейнстримовые компиляторы не делают такой оптимизации).