Ответить
  • Mahagam Senior Member
    офлайн
    Mahagam Senior Member

    2245

    11 лет на сайте
    пользователь #83779

    Профиль
    Написать сообщение

    2245
    # 12 марта 2018 18:08
    Korben_Dallas:

    В упор не вижу, как тут что-то может поменяться от `const`. Поясните.

    строка hello world линкуется в секцию .const, а не пихается в стек, и получает нормальный адрес и незатираемое (как у всего на стеке) значение.
    собственно, так оно у меня и получилось.

    Korben_Dallas:

    Стандартные языки С и С++ никогда не следовали такой логике.

    но до прихода великих оптимизаторов всё так и работало.

    в случае с "вечным циклом" - сами gcc`шники пишут про то, что арифметика у них с переполнением по модулю, и сами же не следуют своей логике.

  • Korben_Dallas Senior Member
    офлайн
    Korben_Dallas Senior Member

    1181

    7 лет на сайте
    пользователь #395360

    Профиль
    Написать сообщение

    1181
    # 12 марта 2018 18:36 Редактировалось Korben_Dallas, 7 раз(а).
    Mahagam:

    Korben_Dallas:

    В упор не вижу, как тут что-то может поменяться от `const`. Поясните.

    строка hello world линкуется в секцию .const, а не пихается в стек, и получает нормальный адрес и незатираемое (как у всего на стеке) значение.
    собственно, так оно у меня и получилось.

    Вы несете какую-то чепуху. Данная функция возвращает указатель на `hw`. Массив `hw` в моем примере - локальный массив и никакой `const` тут ничего никогда поменять не сможет.

    Строковый литерал в С и С++ действительно является объектом со static storage duration (это та самая ваша секция .const), но данная функция возвращает указатель на локальный массив, а не на строковый литерал. Да и генерировать такой строковый литерал уважающий себя компилятор будет только в том случае, если 1) этот литерал кому-то нужен как lvalue, 2) если литерал большой. В данном примере ни одно из этих условий не выполняется. И в данном случае возвращаемое значение функции никакого отношения к этой статической строке в .const не имеет. (Поэтому выдумывать про то, что у вас там что-то "получилось" не надо.)

    Никому в данном конкретном примере никакая строка "с нормальным адресом" не нужна. Что легко видеть и на примере сгенерированного GCC кода: https://godbolt.org/g/bdFyVK . Как видите, компилятор не стал генерировать никакой строки в .const, а просто проинициализировал локальный массив при помощи пары числовых констант

    movabs rax, 8022916924116329800
    mov QWORD PTR [rsp+4], rax
    mov DWORD PTR [rsp+12], 6581362

    Просто и разумно.

    Mahagam:

    Korben_Dallas:

    Стандартные языки С и С++ никогда не следовали такой логике.

    но до прихода великих оптимизаторов всё так и работало.

    ... но не имело никакого отношения к языку С. А разнообразные кул-хацкеры, которые "теорию" читать не любят, а считают, что всему научатся на "практике", приняли это "все работало" за некую незыблемую истину (как Василий Иванович с Петькой в анекдоте про "безногий таракан - не слышит" ). В результате получаются изумленные казусы из разряда "у Коляна из третьего подъезда это всегда работало". Профессиональные С программисты смотрят на беднягу с сожалением...

    Mahagam:

    в случае с "вечным циклом" - сами gcc`шники пишут про то, что арифметика у них с переполнением по модулю, и сами же не следуют своей логике.

    Вы снова что-то выдумываете. Арифметика с переполнением по модулю в С и С++ существует только для беззнаковых типов. Ничего подобного для знаковых типов никто в GCC вам никогда не обещал.

    Добавлено спустя 39 секунд

    Mahagam:

    Korben_Dallas:

    пользуется свободой

    путая понятия "тип" и "число". отсюда и проблема

    Опять какое-то вождение вилами по манной каше пошло.

    Добавлено спустя 7 минут 44 секунды

    Mahagam:

    нормальный ICC - всё сделал как надо.

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

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

    Добавлено спустя 2 минуты 29 секунд

    gooblin:

    Korben_Dallas:

    В упор не вижу, как тут что-то может поменяться от `const`. Поясните.

    может он имел ввиду static?

    Согласно тому, что он написал, он просто не понимает разницы между локальным массивом `hw`и строковым литералом, использованным в качестве инициализатора для этого локального массива.

    При чем здесь `const`, однако, до сих пор не понятно.

    Добавлено спустя 8 минут 58 секунд

    stoGramm:

    Народ, Вы запугали тех кто хочет начать карьеру айтишника.

    Что, лучше про потенцию? :)

    А вообще, как кто-то когда-то метко заметил, "Первая вещь, которую вы должны усвоить про язык С - это то, что в С массив является указателем. Следующая вещь, которую вы должны усвоить про язык С - это то, что в С массив НЕ является указателем."

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

    Et si tu tombes 7 fois Toujours se relever 8
  • Mahagam Senior Member
    офлайн
    Mahagam Senior Member

    2245

    11 лет на сайте
    пользователь #83779

    Профиль
    Написать сообщение

    2245
    # 12 марта 2018 18:59 Редактировалось Mahagam, 1 раз.
    Korben_Dallas:

    Ничего подобного для знаковых типов никто в GCC вам никогда не обещал.

    зато обещает реализация сложения вычитания в CPU. там вообще понятия знаковый/беззнаковый для сложения и вычитания нет. возможно, кроме лишних флагов.
    https://gcc.gnu.org/onlinedocs/gccint/Arithmetic.html - ничего про знаковость для сложения/вычитания не вижу

    Korben_Dallas:

    Опять какое-то вождение вилами по манной каше пошло.

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

  • Korben_Dallas Senior Member
    офлайн
    Korben_Dallas Senior Member

    1181

    7 лет на сайте
    пользователь #395360

    Профиль
    Написать сообщение

    1181
    # 12 марта 2018 19:13 Редактировалось Korben_Dallas, 3 раз(а).
    Mahagam:

    Korben_Dallas:

    Ничего подобного для знаковых типов никто в GCC вам никогда не обещал.

    зато обещает реализация сложения вычитания в CPU. там вообще понятия знаковый/беззнаковый для сложения и вычитания нет. возможно, кроме лишних флагов.
    https://gcc.gnu.org/onlinedocs/gccint/Arithmetic.html - ничего про знаковость для сложения/вычитания не вижу

    Во-первых, буквы `s` и `u` в `ss_plus` и `us_plus` - это как раз таки сокращения для `signed` и `unsigned`. Во-вторых, никакого отношения к рассматриваемой теме приведенная вами ссылка не имеет вообще. Поэтому зачем вы подолжаете спамить обсуждение этой ссылкой - мне в упор не ясно.

    Mahagam:

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

    Совершено верно.

    Mahagam:

    и если тип int долго долго инкрементировать, то в отличие от идеального математического числа, он таки выскочит в отрицательную область.

    А это уже ваши домыслы. Возможно основанные на не относящихся к языку С экспериментах (снова: "безногий таракан - не слышит" )

    Mahagam:

    почему компилятор считает, что инкрементировать int можно бесконечно - неясно.

    Компилятор также считает, что условие

    int i;
    ...
    if (i < i + 1)

    заведомо истинно. А почему он так считает - кристально ясно: потому что стандарт языка открытым текстом разрешает ему так считать.

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

    Et si tu tombes 7 fois Toujours se relever 8
  • Mahagam Senior Member
    офлайн
    Mahagam Senior Member

    2245

    11 лет на сайте
    пользователь #83779

    Профиль
    Написать сообщение

    2245
    # 12 марта 2018 19:52
    Korben_Dallas:

    Во-первых, буквы `s` и `u` в `ss_plus` и `us_plus`

    Это только для saturated арифметики, вторая буква s про это говорит.

    Добавлено спустя 9 минут 52 секунды

    Korben_Dallas:

    int i;
    ...
    if (i < i + 1)
    заведомо истинно.

    Для абстракьного целого - истинно, для переполнимого типа int - нет.

    И ещё, для чего с с++11 ввели возможность переопределять значение nullptr на ненулевое значение?
    Уж не для того ли, чтобы можно было как раз писать int *p = 0; *p= val; :shuffle:

  • Korben_Dallas Senior Member
    офлайн
    Korben_Dallas Senior Member

    1181

    7 лет на сайте
    пользователь #395360

    Профиль
    Написать сообщение

    1181
    # 12 марта 2018 20:32 Редактировалось Korben_Dallas, 6 раз(а).
    Mahagam:

    Korben_Dallas:

    int i;
    ...
    if (i < i + 1)
    заведомо истинно.

    Для абстракьного целого - истинно, для переполнимого типа int - нет.

    В языках С и С++ трактовка такого условия как заведомо истинного полностью соответствует спецификациям этих языков. И современные компиляторы С и С++ видят больше пользы именно в такой трактовке знаковой арифметики. Strict-overflow semantics, baby! Как говорится, deal with it.

    Mahagam:

    И ещё, для чего с с++11 ввели возможность переопределять значение nullptr на ненулевое значение?
    Уж не для того ли, чтобы можно было как раз писать int *p = 0; *p= val; :shuffle:

    Вопрос не ясен. В языке С++ `nullptr` является значением типа `std::nullptr_t`. Это не числовое значение и "нулевым" или "ненулевым" оно быть не может никак.

    Если вы спрашиваете, зачем в язык С++ вообще ввели `nullptr` - так это для того, чтобы устранить неприятные паразитные эффекты использования `0` в качестве null pointer constant. `NULL` предназначен для использования только в указательных контекстах, но из-за `#define NULL 0` в С++ можно было писать такие странные вещи, как `int i = NULL;` и этот код молча компилировался компилятором. (Он и сейчас обычно компилируется, ибо ни у кого пока не хватает смелости заменить `#define NULL 0` на `#define NULL nullptr`.)

    При этом роль литерального `0` в качестве null pointer constant никто не отменял и отменять не собирается. По-прежнему гарантируется, что `int *p = 0` будет порождать правильное платформенно-зависимое null pointer value. Так что не надейтесь :)

    Et si tu tombes 7 fois Toujours se relever 8
  • Mahagam Senior Member
    офлайн
    Mahagam Senior Member

    2245

    11 лет на сайте
    пользователь #83779

    Профиль
    Написать сообщение

    2245
    # 12 марта 2018 20:42
    Korben_Dallas:

    ибо ни у кого пока не хватает смелости заменить `#define NULL 0` на `#define NULL nullptr

    Тогда о чём тут пишут?

  • Korben_Dallas Senior Member
    офлайн
    Korben_Dallas Senior Member

    1181

    7 лет на сайте
    пользователь #395360

    Профиль
    Написать сообщение

    1181
    # 12 марта 2018 21:04 Редактировалось Korben_Dallas, 15 раз(а).
    Mahagam:

    Korben_Dallas:

    ибо ни у кого пока не хватает смелости заменить `#define NULL 0` на `#define NULL nullptr

    Тогда о чём тут пишут?

    О том же, о чем и я. В "классическом" С++ `NULL` мог быть (только?) константным нулем, обычно типа `int` или `long`. Начиная с С++11 `NULL` может быть как буквальным нулем, так и `nullptr`. Но пока, насколько я знаю, ни одна из популярных реализаций не осмелилась перейти с `#define NULL 0` на `#define NULL nullptr`.

    Почему они не спешат? Не знаю. Можно заметить, что, например, в таком коде

    void foo(long) { ... }
    void foo(void *) { ... }

    foo(NULL);

    в "классическом" С++ должна вызваться именно первая функция (как ни странно). А после перехода на `#define NULL nullptr` тихонько начнет вызваться вторая. Возможно именно такие соображения заставляют нынешние реализации "осторожничать" с переходом на `#define NULL nullptr`. Но это очень слабый аргумент. Я лишь предполагаю.

    Хотя я вижу, ребята в GCC уже давно подсуетились. Код `int i = NULL;` выдает предупреждение. Это еще не полноценный `#define NULL nullptr`, ибо тогда была бы ошибка, но уже шаг в этом направлении. Простой эксперимент показывает, что они определяют `NULL`, как некоторый внутренний идентификатор `__null`, в контексте перегрузки ведущий себя как значение типа `long`.
    ---

    C++11 запретил использовать нетривиальные константые выражения в качестве null pointer constant

    int *p = 42 - 2 * 21;
    // Корректно в С и в С++98, ошибка в С++11 и далее

    но трактовка буквального `0` не поменялась.

    Et si tu tombes 7 fois Toujours se relever 8
  • Mahagam Senior Member
    офлайн
    Mahagam Senior Member

    2245

    11 лет на сайте
    пользователь #83779

    Профиль
    Написать сообщение

    2245
    # 13 марта 2018 00:00 Редактировалось Mahagam, 2 раз(а).
    Korben_Dallas:

    Да и генерировать такой строковый литерал уважающий себя компилятор будет только в том случае,

    если он плюсовый, в случае си - все компиляторы генерят что-то подобное:
    (втыкаем опцию -xc и получаем)

    .LC0:
    .string "Hello World"
    foo:
    mov eax, OFFSET FLAT:.LC0
    ret

    а на "бесконечный цикл" for (int i=0; i>=0; ++i)
    все компиляторы внезапно начинают генерить код, если вместо инта им подсунуть short int.

    short int foo()
    {
    short int mvar = 0;
    int i;

    for (i = 0; i>= 0; i++) {
    mvar = i;
    }
    return mvar;
    }

    круче всех всегда оказывается шланг 3.0, он выдаёт код вида

    foo: # @foo
    mov EAX, -1
    ret

    (вместо -1 могут быть другие константы, если играться с short/ не short)

    остальные компиляторы дают что-то типа

    foo:
    xor eax, eax
    jmp .L2
    .L3:
    mov eax, edx
    .L2:
    mov edx, eax
    add dx, 1
    jns .L3
    rep ret

    это GCC 7.3

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

  • Korben_Dallas Senior Member
    офлайн
    Korben_Dallas Senior Member

    1181

    7 лет на сайте
    пользователь #395360

    Профиль
    Написать сообщение

    1181
    # 13 марта 2018 01:19 Редактировалось Korben_Dallas, 14 раз(а).
    Mahagam:

    Korben_Dallas:

    Да и генерировать такой строковый литерал уважающий себя компилятор будет только в том случае,

    если он плюсовый, в случае си - все компиляторы генерят что-то подобное:
    (втыкаем опцию -xc и получаем)

    .LC0:
    .string "Hello World"
    foo:
    mov eax, OFFSET FLAT:.LC0
    ret

    Во-первых, в ссылке на godbolt, которую я приводил ранее для этого кода, уже стоит опция `-x c` (!). И никакого `.string "Hello World"` там нет.

    Во-вторых, что бы за результаты вы ни получали в своих экспериментах, они все равно не имеют никакого значения. Мне совершенно не ясно, что вы нам тут пытаетесь продемонстрировать. Что есть компиляторы, которые в ответ на входной "мусор" генерируют выходной "мусор", соответствующий вашим ожиданиям? Но это никому не интересно. Никому не нужен "мусор", независимо от степени его соответствия чьим-то ожиданиям. А undefined behavior - это именно оно.

    Mahagam:

    а на "бесконечный цикл" for (int i=0; i&gt;=0; ++i)
    все компиляторы внезапно начинают генерить код, если вместо инта им подсунуть short int.

    О, разумеется, начинают! Замена `int` на `short` или `signed char` - это приниципиальнейшее (!) изменение, которое очень сильно все меняет. Вы, боюсь, демонстрируете свое незнание языка С.

    В языке С выражение `++i` определяется как эквивалент `i += 1`, что в свою очередь эквивалентно `i = i + 1` (только операнд вычисляется один раз, а не два). Как только в качестве операнда бинарного `+` используется операнд "маленького" целого типа (`_Bool`, `signed/unsigned char`, `signed/unsigned short` или битовое поле), это операнд подвергается т.наз. integral promotions и неявно преобразуется к типу `int`. Вычисление суммы `i + 1` делается в домене типа `int`, а затем результат преобразуется обратно к типу `short` перед занесением обратно в `i`. То есть выражение `++i` не самом деле рассматривается языком С как `i = (short) ((int) i + 1)`. Так было всегда в языке С.

    На вашей платформе, очевидно, тип `int` имеет боле широкий диапазон, чем тип `short`. Это значит, что даже если изначально переменная `i` имела "предельное" значение `SHRT_MAX`, при вычислении `(int) i + 1` в домене типа `int` никакого переполнения не произойдет (!). "Переполнение" произойдет позже, когда полученный результат будет преобразовываться в значение типа `short` перед запихиванием его обратно в переменную `i`.

    И вот тут то и заключается ключевой момент (!): "переполнение" при выполнении преобразования от более широкого знакового типа к более узкому не вызывает неопределенного поведения, а вызывает поведение, определяемое реализацией (implementation-defined behavior).

    Это - фундаментальное отличие от ситуации с типом `int`. В случае с `int` мы получали переполнение при вычислении арифметической операции `i + 1`, что вызывает undefined behavior. В случае с `short` сама арифметическая операция `i + 1` переполнения не вызывает, а "переполнение" возникает при выполнении преобразования результата обратно в `short` при присваивании, что является implementation-defined behavior.

    Замечаете гигантскую разницу? В одном случае undefined behavior есть, а в другом - нет. Вот это и привело к разнице ваших результатов трансляции.

    Кстати, от undefined behavior вас спасло то, что на вашей платформе тип `int` имеет боле широкий диапазон, чем тип `short`. На некоей другой платформе, где `short` и `int` имеют одинаковый диапазон, integral promotions вас бы не спасли и имел бы место undefined behavior даже для варианта с `short`.

    Mahagam:

    речь про бесконечный цикл уже не идёт ни разу

    Боюсь что вы либо что-то выдумываете, либо втихаря подтасовываете. Ваш код:

    Clang: https://godbolt.org/g/Mk513D
    GCC: https://godbolt.org/g/o4fzxP

    Но в любом случае, еще раз: все это не имеет никакого значения. Экспериментальные исследования undefined behavior - это интересное развлечение, но практической пользы от этого никакой нет (кроме, разве что, образовательной). Неопределенное поведение может проявлять себя непредсказуемым разнообразием вариантов, в зависимости от дней недели и погоды на Марсе. Форматировать вам жесткий диск ваша программа не станет и пресловутые "nasal demons" тоже не полетят (не уверен насчет последнего), но и пользы от undefined когда все равно никакой нет и не будет.

    Mahagam:

    а почему он вдруг начинает считать, что пора бы сгенерить код? видимо потому что стандарт языка открытым текстом разрешает ему так считать.

    Совершенно верно! Неопределенное поведение - это высшая форма компиляторной свободы в языках С и С++: гони, компилятор, любую чушь - все сгодится.

    Et si tu tombes 7 fois Toujours se relever 8
  • gooblin Senior Member
    офлайн
    gooblin Senior Member

    3790

    15 лет на сайте
    пользователь #6965

    Профиль
    Написать сообщение

    3790
    # 13 марта 2018 01:35

    Korben_Dallas, Mahagam, мир вам добрые люди :)

    давайте уже остановится на вот чем:

    В идеале стандарту языка C должен соответствовать как ваш код так и ваши компиляторы, при условии что выходите получить portable код на разных execution environments. Хотя на чистом C сейчас только и пишут что-то платформо-зависимое :).

    Дайте лучше пару советов дельных новичкам как лучше изучить программирование с вашей точки зрения.

    НКХЖЕХВ
  • Korben_Dallas Senior Member
    офлайн
    Korben_Dallas Senior Member

    1181

    7 лет на сайте
    пользователь #395360

    Профиль
    Написать сообщение

    1181
    # 13 марта 2018 01:45 Редактировалось Korben_Dallas, 5 раз(а).
    gooblin:

    Хотя на чистом C сейчас только и пишут что-то платформо-зависимое :)

    Отнюдь. Я работаю в области EDA (Electronic Design Automation), где позиции С еще весьма сильны, хоть и уступили уже значительно С++. Ничего платформенно-зависимого мы не пишем, да и не могли бы, ибо основная целевая платформа у нас - Linux, Linux и Linux, в то время как повседневная разработка делается именно под Windows. Это вполне штатная ситуация.

    gooblin:

    Дайте лучше пару советов дельных новичкам как лучше изучить программирование с вашей точки зрения.

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

    Et si tu tombes 7 fois Toujours se relever 8
  • gooblin Senior Member
    офлайн
    gooblin Senior Member

    3790

    15 лет на сайте
    пользователь #6965

    Профиль
    Написать сообщение

    3790
    # 13 марта 2018 02:11
    Korben_Dallas:

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

    Да забейте, сколько людей столько мнений. Я например давно уже вышел из того возраста когда своем мнение представляется единственно правильным, ошибочно полагая, что огромный опыт дает право так думать. :) А новички, действительно стремящиеся к знаниям, с удовольствием послушают дельные советы.

    НКХЖЕХВ
  • Mahagam Senior Member
    офлайн
    Mahagam Senior Member

    2245

    11 лет на сайте
    пользователь #83779

    Профиль
    Написать сообщение

    2245
    # 13 марта 2018 02:37 Редактировалось Mahagam, 1 раз.
    Korben_Dallas:

    Совершенно верно! Неопределенное поведение - это высшая форма компиляторной свободы в языках С и С++: гони, компилятор, любую чушь - все сгодится.

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

    другим нужен си именно как средство взаимодействия с железом, такие требуют чтобы компилятор работал с переполнениями знаковых чисел (-fwrapv решает проблему), требуют прямой доступ по нулевому адресу, пишут код вида (узнаёте того кто это активно использовал, да?)

    float InvSqrt(float x)
    {
    float xhalf = 0.5f * x;
    int i = *(int*)&x;
    i = 0x5f375a86 - (i >> 1);
    x = *(float*)&i;
    x = x * (1.5f - xhalf * x * x);
    return x;
    }

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

    вот и получается, что кому-то UB и высшая форма свободы компилятора, а кому-то - максимальное использование особенностей железа.

  • Korben_Dallas Senior Member
    офлайн
    Korben_Dallas Senior Member

    1181

    7 лет на сайте
    пользователь #395360

    Профиль
    Написать сообщение

    1181
    # 13 марта 2018 03:02 Редактировалось Korben_Dallas, 3 раз(а).
    Mahagam:

    требуют прямой доступ по нулевому адресу, пишут код вида (узнаёте автора, да?)

    float InvSqrt(float x)
    {
    float xhalf = 0.5f * x;
    int i = *(int*)&x;
    i = 0x5f375a86 - (i >> 1);
    x = *(float*)&i;
    x = x * (1.5f - xhalf * x * x);
    return x;
    }

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

    Так речь-то как раз идет о том, что в 99 процентах случаях из 100 есть возможность написать [более] чистый код, который будет обладать той же самой оптимальностью.

    Вышеприведенный код, к сожалению, является ярко-выраженным "гамнокодом" с точки зрения языка С, из-за грубого нарушения правил strict aliasing. Но это еще можно оправдать тем, что в те времена, когда он был написан, просто не было хороших альтернатив. Возможность использования `union` для переинтерпретации объектов в памяти (type punning) было официально закреплена только в Technical Corrigendum 3 к стандарту C99. И сегодня тот же код можно запросто переписать с существенно меньшим количеством грязных хаков

    float InvSqrt(float x)
    {
    union { float f; int i; } tp = { .f = x };
    tp.i = 0x5f375a86 - (tp.i >> 1);
    return tp.f * (1.5f - 0.5f * x * tp.f * tp.f);
    }

    Понятно, что полностью портабельным он от этого не стал, но опасность переупорядочивания критических операций компилятором из-за таких хаков как `int i = *(int*)&x;` и `x = *(float*)&i;` тем не менее исчезла.

    Et si tu tombes 7 fois Toujours se relever 8
  • Mahagam Senior Member
    офлайн
    Mahagam Senior Member

    2245

    11 лет на сайте
    пользователь #83779

    Профиль
    Написать сообщение

    2245
    # 13 марта 2018 12:17

    ну, знать стандарты - это хорошо.
    но и знать ключи компилятора - тоже неплохо. всего лишь -fwrapv -fno-delete-null-pointer-checks и всё работает "как на борланде" :trollface: и Колян из третьего подъезда одобрит, и компилятор вдруг увидит смысл там, где его вдруг не было.

  • Korben_Dallas Senior Member
    офлайн
    Korben_Dallas Senior Member

    1181

    7 лет на сайте
    пользователь #395360

    Профиль
    Написать сообщение

    1181
    # 13 марта 2018 19:32 Редактировалось Korben_Dallas, 13 раз(а).
    Mahagam:

    ну, знать стандарты - это хорошо.
    но и знать ключи компилятора - тоже неплохо. всего лишь -fwrapv -fno-delete-null-pointer-checks и всё работает "как на борланде" :trollface: и Колян из третьего подъезда одобрит, и компилятор вдруг увидит смысл там, где его вдруг не было.

    Ну это уже что-то из области типичного форумного нытья: "На -O1 у меня все работает, а на -O3 - все рушится. Виноваты в этом, вестимо, именно криворукие студенты-разработчики GCC, так как я - д'Артаньян. Поэтому я вынужден пользоваться -O1."

    Да и зачем так мелочиться? С таким же успехом можно указать в командной строке `-x assembler-with-cpp` или `-x f77` и горизонты возможностей языка С, поддерживаемые данным компилятором языка C, вообще расширятся неимоверно ("вдруг увидит смысл там, где его вдруг не было" ) :)

    Загонять язык С в какие-то свои, взятые с потолка рамки неопределенного поведения путем манипуляции ключами командной строки ради компиляции "хакерского" кода - занятие, уместное при написании каких-нибудь драйверов и операционных систем. К языку С это не имеет прямого отношения. В С программировании подобные ключи компилятора предназначены в первую очередь для того, чтобы 1) обходить возможные баги оптимизатора, 2) компилировать накопленный и неподдерживаемый старинный "гамнокод". Но ни в коем случае не для того, чтобы тащить гору к Магомету и предоставлять возможность для написания нового "гамнокода".

    Et si tu tombes 7 fois Toujours se relever 8
  • Mahagam Senior Member
    офлайн
    Mahagam Senior Member

    2245

    11 лет на сайте
    пользователь #83779

    Профиль
    Написать сообщение

    2245
    # 13 марта 2018 23:36
    Korben_Dallas:

    На -O1 у меня все работает, а на -O3 - все рушится. Виноваты в этом, вестимо, именно криворукие студенты-разработчики GCC, так как я - д'Артаньян. Поэтому я вынужден пользоваться -O1

    да ладно, О3 - прекрасный детектор говнокода, но говнокода не в вашем понимании.

    Korben_Dallas:

    и горизонты возможностей языка С, поддерживаемые данным компилятором языка C, вообще расширятся неимоверно

    давайте будем честными, и вместо "расширятся" скажем "не будут сужены".

    Korben_Dallas:

    Загонять язык С в какие-то свои, взятые с потолка рамки неопределенного поведения путем манипуляции ключами командной строки ради компиляции "хакерского" кода

    да не бывает полностью неопределённого поведения. вопрос в том что считать неопределённым, и для какого случая.
    да и вроде ключи как только расширяют рамки )))

    Korben_Dallas:

    уместное при написании каких-нибудь драйверов и операционных систем.

    так язык си для подобного по большей части и используют, ну и embedded, а в embedded все возможности доступа к железу востребованы. там на си нельзя только переключатель контекста задачи написать. и обработчик прерываний для старых МК. начиная с какого-то кортекса (с Cortex-M3 вроде) даже обработчик прерывания можно без ассемблерных вставок наваять.

    чем везде видеть UB, и ограничивать язык придуманными правилами, лучше взять язык выше уровнем и не мучать себя )

  • gooblin Senior Member
    офлайн
    gooblin Senior Member

    3790

    15 лет на сайте
    пользователь #6965

    Профиль
    Написать сообщение

    3790
    # 14 марта 2018 00:30 Редактировалось gooblin, 1 раз.
    Mahagam:

    так язык си для подобного по большей части и используют, ну и embedded, а в embedded все возможности доступа к железу востребованы

    В embedded с фришными компиляторами типа gcc раньше беда была. Потому что никто никому ничего не должен. Найдешь баг, отпишешь, и или месяц жди либо сам патч присылай. Типа сам нашел - сам исправил - возьми с полки пирожок. :) Было у меня лет надцать назад c gcc 2.96 такое - неправильно генерил объектные файлы для таргета a.out при кросс-компиляции. И руки были связаны - надо было именно под gcc 2.96 и именно a.out - таковы были требования.

    НКХЖЕХВ
  • Mahagam Senior Member
    офлайн
    Mahagam Senior Member

    2245

    11 лет на сайте
    пользователь #83779

    Профиль
    Написать сообщение

    2245
    # 14 марта 2018 01:07

    gooblin, я больше проприетарными компиляторами пользовался. IAR, например, любил выдавать страннейший код на высоких уровнях оптимизации. и особенно при работе с плавучкой. но что там последние лет 5 деется - не знаю.