Программистские задачки и хитрости

Re: Программистские задачки и хитрости

Сообщение netraider » 13 дек 2019, 10:19

Отсылки к флагам компиляции были сделаны для того, что бы описать где именно с точки зрения языка могут быть лазейки для 'void main'. Есть понятие implementation defined, для того что бы понять какое поведение скрыто за этим термином - нужно смотреть сопроводительную документацию на конкретный компилятор.

Разумеется можно не смотреть, но тогда для strictly conformming программ стандарт сразу запрещает 'void main'. Собственно уже на этом можно было и остановиться.

Доказательство компилятором заранее обречены на провал. К примеру один из известных компиляторов С++ по умолчанию умеет привязывать временные объекты к не константным ссылкам. Делает ли это эту фичу валидной с точки зрения языка? разумеется нет.

Также и здесь. GCC "по умолчанию" тоже много чего позволяет:

"By default, GCC provides some extensions to the C language".
...
"GNU C provides several language features not found in ISO standard C"

Но это не делает все эти extensions и language features допустимыми с точки зрения языка.
ибо в нём ни о каких опциях gcc не говорится, т.е. используем gcc "по дефолту".

Использование "gcc по дефолту" в рассматриваемом контексте ни к чему хорошему не приведет. Есть стандарт языка, есть conforming implementation. Разумеется нужно понимать, что разработчики компиляторов должны поддерживать совместимость с огромным количеством legacy кода и они не могут просто так взять и добавить в 'default' набор все флаги, необходимые для полного соответствия стандарту. Поэтому это нужно делать самостоятельно, но для этого нужно как минимум обратиться к сопроводительной документации. В которой для gcc явно написано как отключить "language features not found in ISO standard C", как указать версию стандарта и т.п. и сделать (или хотя бы попытаться сделать) из gcc conforming implementation.

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

Увы, "синтаксических ошибок" в примере нет. В одно месте есть нарушение constraint(диагностируемое UB) и не диагностируемое UB в другом месте.
И кстати вот это самое неопределенное поведение в форме концепции, как показывает практика, очень часто вызывает непонимание.

Приблизительное определение:
3.4.3/1
Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). EXAMPLE: An example of undefined behavior is the behavior on integer overflow.

На самом деле все усугубляет отсутствие диагностики UB на этапе компиляции. Здесь все дело в том что детектирование всех возможных вариантов неопределенного поведения требует колоссальных усилий со стороны разработчиков компилятора. А в некоторых случаях это детектирование и вовсе невозможно. Из-за этого от компилятора и не требуют этой диагностики. Да, разумеется, в некоторых случаях разумеется диагностика требуется стандартом. Это как раз нарушения требований 'shall' и 'shall not' в C, а также в некотором приближении понятие 'ill-formed' в С++ (там отдельные нюансы).

Но в некоторых случаях компиляторы способны детектировать UB и выдавать сообщения об этом. А в некоторых случаях должны это делать.

5.1.1.3/1
A conforming implementation shall produce at least one diagnostic message (identified in an imple-mentation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined orimplementation-defined.

И примечание к этому:
5.1.1.3/1(9)
The intent is that an implementation should identify the nature of, and where possible localize, each violation. Of course,an implementation is free to produce any number of diagnostics as long as a valid program is still correctly translated. It may also successfully translate an invalid program.


Особенно нужно обратить внимание на последнее предложение. Собственно это я и имел виду по некорректностью примера с точки зрения языка.

Резюмируя: Есть язык С -> есть стандарт языка -> стандарт описывает требования, накладываемые на conforming implementation -> большинство компиляторов не являются conforming implementations по умолчанию в силу причин указанных выше -> но они предоставляют набор флагов, которые "превращают" их в conforming implementations -> используем эти флаги -> видим ошибки в коде (иногда не все, т.к. диагностика UB не всегда требуется от компилятора).

Но можно более продуктивно, без всяких компиляторов и флагов: берем стандарт языка -> видим ошибки в коде:
1) 'void main' стандарт не разрешает (номер пункта стандарта я приводил).
2) при несоответствии количества аргументов в printf колучеству спецификаторов возникает UB (номер пункта стандарта я приводил). В силу определения - UB может приводить к якобы корректному наблюдаемому поведению. Но факт наличия UB это не отменяет (да даже тот же gcc умеет выбрасывать неиспользуемую переменную, поэтому наблюдаемое поведение программы изменяется в зависимости от флагов).

К пункту 1 можно добавить примечание: конкретная conforming implementation может добавить разрешить 'void main' как часть implementation defined поведения (упомянутый GCC этого не делает).

При выкручивании диагностических сообщений на максимальный уровень соответствия стандарту обе этих ошибки(UB) прекрасно диагностируются большинством компиляторов(в т.ч. и gcc).


--std=iso9899:2017 --pedantic --pedantic-errors -Werror=format

Код: Выделить всёРазвернуть
<source>: In function 'print':

<source>:5:28: error: format '%d' expects a matching 'int' argument [-Werror=format=]

    5 |    printf("print: a=%d, b=%d\n", a), b;
      |                           ~^
      |                            int

<source>: At top level:

<source>:8:6: error: return type of 'main' is not 'int' [-Wmain]

    8 | void main(void) {
      |      ^~~~


Иначе получается забавный факт: с помощью не conforming implementation ("ggc "по дефолту") выполняется попытка доказательства корректности invalid program (которая содержит два места с неопределенным поведением), gcc ведь всплыл в обсуждении почти сразу. Увы, стандарт в этом случае остается в стороне, и не описывает то, что должно получится в результате. Но именно о результате и идет речь в примере.

Какой там код получился - "валидный"/”законный” или нет, в результате компиляции invalid program c помощью non conforming implementation - рассуждать абсолютно бессмысленно.


PS: Замечу, что все мои выводы полностью аргументированы и подкреплены ссылками на стандарт и цитатами из него же.
--
At the nanometer level, the world is made of rubber (с)
netraider
Мастер
 
Сообщения: 206
Зарегистрирован: 23 май 2015, 10:47
Откуда: Комсомольск-на-Амуре
Репутация: 47
Настоящее имя: Юрий

Re: Программистские задачки и хитрости

Сообщение UAVpilot » 13 дек 2019, 19:26

netraider писал(а):рассуждать абсолютно бессмысленно

Именно! Ибо пример/задачка совсем о другом.
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
UAVpilot
Мастер
 
Сообщения: 20304
Зарегистрирован: 17 апр 2012, 14:58
Откуда: Москва
Репутация: 4856
Заслуга: c781c134843e0c1a3de9
Медальки:
Настоящее имя: Сергей

Re: Программистские задачки и хитрости

Сообщение netraider » 17 дек 2019, 12:51

UAVpilot писал(а):
netraider писал(а):рассуждать абсолютно бессмысленно

Именно! Ибо пример/задачка совсем о другом.

Любой результат будет допустимым. Вот поэтому и бессмысленно. Либо же нужно изменить формулировку - "Пример/задачка содержит UB. Нужно объяснить конкретный наблюдаемый вариант (их может быть несколько)". С такой формулировкой я согласен. Только нужно понимать что поведение в случае наличия UB остается за рамками стандарта языка. Соответственно ни о каком правильном вараинте ответа не может быть и речи, т.к. "правильность" нельзя доказать.
--
At the nanometer level, the world is made of rubber (с)
netraider
Мастер
 
Сообщения: 206
Зарегистрирован: 23 май 2015, 10:47
Откуда: Комсомольск-на-Амуре
Репутация: 47
Настоящее имя: Юрий

Re: Программистские задачки и хитрости

Сообщение UAVpilot » 17 дек 2019, 23:14

Задание/вопрос было предельно короткое и ясное. :)
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
UAVpilot
Мастер
 
Сообщения: 20304
Зарегистрирован: 17 апр 2012, 14:58
Откуда: Москва
Репутация: 4856
Заслуга: c781c134843e0c1a3de9
Медальки:
Настоящее имя: Сергей

Re: Программистские задачки и хитрости

Сообщение MX_Master » 18 апр 2020, 13:34

Во я ламер а.. :thinking: товарищи-программисты, как в С объявить двумерный массив, расположенный по точно указанному адресу памяти?
Аватара пользователя
MX_Master
Мастер
 
Сообщения: 5853
Зарегистрирован: 27 июн 2015, 19:45
Откуда: Алма-Ата
Репутация: 2607
Медальки:
Настоящее имя: Миша

Re: Программистские задачки и хитрости

Сообщение Duhas » 18 апр 2020, 14:49

ну в си нет как таковых двумерных массивов, вопрос только как это выглядит в коде )

память по конкретному адресу откуда взялась?

обращаться то как туда хочется?
Duhas
Мастер
 
Сообщения: 1564
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 237
Настоящее имя: Андрей

Re: Программистские задачки и хитрости

Сообщение merkwurdigliebe » 18 апр 2020, 15:05

Код: Выделить всёРазвернуть
#include <stdio.h>
#include <stdlib.h>
int main()
{
   int (*a)[16] = malloc(sizeof(int)*16*16);
   printf("%d\n", &a[1][0] - &a[0][0]);
}
merkwurdigliebe
Мастер
 
Сообщения: 413
Зарегистрирован: 17 дек 2013, 22:14
Откуда: Москва
Репутация: 396
Медальки:

Re: Программистские задачки и хитрости

Сообщение Duhas » 18 апр 2020, 15:21

так то оно так, но вопрошающий тут о конкретном адресе заикается )
Duhas
Мастер
 
Сообщения: 1564
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 237
Настоящее имя: Андрей

Re: Программистские задачки и хитрости

Сообщение merkwurdigliebe » 18 апр 2020, 15:37

ну я уж думаю он догадается маллок на конкретный адрес заменить...
merkwurdigliebe
Мастер
 
Сообщения: 413
Зарегистрирован: 17 дек 2013, 22:14
Откуда: Москва
Репутация: 396
Медальки:

Re: Программистские задачки и хитрости

Сообщение Duhas » 18 апр 2020, 15:39

коли вопрошает - могут быть варианты ) я почему то в контексте его других постов подозреваю что он что-то желает в "условно аппаратную" часть записать ) пускай колется чего ваяет )
Duhas
Мастер
 
Сообщения: 1564
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 237
Настоящее имя: Андрей

Re: Программистские задачки и хитрости

Сообщение MX_Master » 18 апр 2020, 17:25

Колюсь.. :) Вощем, выделяю кусочек общей памяти в чётко заданной области SRAM, для взаимовыгодного общения процессоров внутри одного чипа.

#include <stdint.h>

uint32_t (*array)[кол-во столбцов] = (void*) адрес; // получилось вот так (кол-во рядов не указываю)

array[0][0] = 1; // использую вот так
Аватара пользователя
MX_Master
Мастер
 
Сообщения: 5853
Зарегистрирован: 27 июн 2015, 19:45
Откуда: Алма-Ата
Репутация: 2607
Медальки:
Настоящее имя: Миша

Re: Программистские задачки и хитрости

Сообщение Duhas » 18 апр 2020, 17:56

сама память уже выделена где-то ?
Duhas
Мастер
 
Сообщения: 1564
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 237
Настоящее имя: Андрей

Re: Программистские задачки и хитрости

Сообщение MX_Master » 18 апр 2020, 17:59

Duhas писал(а):сама память уже выделена где-то ?

Да. Проверил. Кроме меня там никто не ковыряется :mrgreen:
Аватара пользователя
MX_Master
Мастер
 
Сообщения: 5853
Зарегистрирован: 27 июн 2015, 19:45
Откуда: Алма-Ата
Репутация: 2607
Медальки:
Настоящее имя: Миша

Re: Программистские задачки и хитрости

Сообщение UAVpilot » 18 апр 2020, 18:21

MX_Master писал(а):Во я ламер а.. :thinking: товарищи-программисты, как в С объявить двумерный массив, расположенный по точно указанному адресу памяти?

Для какого компилятора? :)

И тебе как выделить, абы как или чтоб туда гарантированно никто другой не влез? :hehehe:
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
UAVpilot
Мастер
 
Сообщения: 20304
Зарегистрирован: 17 апр 2012, 14:58
Откуда: Москва
Репутация: 4856
Заслуга: c781c134843e0c1a3de9
Медальки:
Настоящее имя: Сергей

Re: Программистские задачки и хитрости

Сообщение Duhas » 18 апр 2020, 18:24

дык она замаллочена или просто решено писать вон туда ? ))
Duhas
Мастер
 
Сообщения: 1564
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 237
Настоящее имя: Андрей

Re: Программистские задачки и хитрости

Сообщение MX_Master » 18 апр 2020, 19:23

Мне в общем виде, чтобы для большинства компилеров эффект был одинаковый.

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

Я б, канеш, воспользовался стандартным механизмом коммуникации промеж пиоцессоров, но он настолько убогий, что без слез не взглянешь...
Аватара пользователя
MX_Master
Мастер
 
Сообщения: 5853
Зарегистрирован: 27 июн 2015, 19:45
Откуда: Алма-Ата
Репутация: 2607
Медальки:
Настоящее имя: Миша

Re: Программистские задачки и хитрости

Сообщение Duhas » 18 апр 2020, 20:13

я о том что стоит не просто писать в понравившийся адрес а выделить память в одном процессе и отдать указатель на нее другому.
Duhas
Мастер
 
Сообщения: 1564
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 237
Настоящее имя: Андрей

Re: Программистские задачки и хитрости

Сообщение MX_Master » 18 апр 2020, 20:27

Андрей, общаться будут не 2 процесса промеж собой, а 2 разных процессора разной архитектуры :)
Аватара пользователя
MX_Master
Мастер
 
Сообщения: 5853
Зарегистрирован: 27 июн 2015, 19:45
Откуда: Алма-Ата
Репутация: 2607
Медальки:
Настоящее имя: Миша

Re: Программистские задачки и хитрости

Сообщение UAVpilot » 18 апр 2020, 20:51

MX_Master писал(а):Мне в общем виде, чтобы для большинства компилеров эффект был одинаковый.

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

MX_Master писал(а):Гарантированно в разнопроцессорных чипах может быть только по обоюдному согласию. Но это далеко ещё не факт. Ибо кто-то третий в новых версиях софта всегда может подумать иначе.

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

MX_Master писал(а):Я б, канеш, воспользовался стандартным механизмом коммуникации промеж пиоцессоров, но он настолько убогий, что без слез не взглянешь...

Но он наверняка позволяет синхронизировать обращения к общей памяти, например чтобы не получилось, что один процессор пытаясь считать uint32_t не считает 2 байта от нового значения и 2 байта от старого, сунувшись туда в момент, когда другой обновляет это значение.
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
UAVpilot
Мастер
 
Сообщения: 20304
Зарегистрирован: 17 апр 2012, 14:58
Откуда: Москва
Репутация: 4856
Заслуга: c781c134843e0c1a3de9
Медальки:
Настоящее имя: Сергей

Re: Программистские задачки и хитрости

Сообщение MX_Master » 19 апр 2020, 05:30

Добавить область памяти в скрипт линковщика - идея хорошая. Правда, от третьих лиц она не спасёт, но хорошая.

В чипе есть небольшая область под spinlock'и, ею можно воспользоваться.
Аватара пользователя
MX_Master
Мастер
 
Сообщения: 5853
Зарегистрирован: 27 июн 2015, 19:45
Откуда: Алма-Ата
Репутация: 2607
Медальки:
Настоящее имя: Миша

Пред.След.

Вернуться в Оффтоп

Кто сейчас на конференции

Зарегистрированные пользователи: Alexa [Bot], andrein, AVK74, Андрей Г., Bing [Bot], Cvazist, er931, Evgen24, Gestap, Google [Bot], Lexxa, loi_28, Majestic-12 [Bot], Malyarka74, Nick, NickSon, niksooon, pegas13, Provodnik, Rom327, seet46, sima8520, steelcam, tsurika, Umnik, verser, vitzin, Yandex [bot], Леонид Владимирович, шпиндель

Reputation System ©'