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

netraider
Мастер
Сообщения: 209
Зарегистрирован: 23 май 2015, 10:47
Репутация: 49
Настоящее имя: Юрий
Откуда: Москва
Контактная информация:

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

Сообщение netraider »

Отсылки к флагам компиляции были сделаны для того, что бы описать где именно с точки зрения языка могут быть лазейки для '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 (с)
Аватара пользователя
Serg
Мастер
Сообщения: 21923
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5181
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

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

Сообщение Serg »

netraider писал(а):рассуждать абсолютно бессмысленно
Именно! Ибо пример/задачка совсем о другом.
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
netraider
Мастер
Сообщения: 209
Зарегистрирован: 23 май 2015, 10:47
Репутация: 49
Настоящее имя: Юрий
Откуда: Москва
Контактная информация:

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

Сообщение netraider »

UAVpilot писал(а):
netraider писал(а):рассуждать абсолютно бессмысленно
Именно! Ибо пример/задачка совсем о другом.
Любой результат будет допустимым. Вот поэтому и бессмысленно. Либо же нужно изменить формулировку - "Пример/задачка содержит UB. Нужно объяснить конкретный наблюдаемый вариант (их может быть несколько)". С такой формулировкой я согласен. Только нужно понимать что поведение в случае наличия UB остается за рамками стандарта языка. Соответственно ни о каком правильном вараинте ответа не может быть и речи, т.к. "правильность" нельзя доказать.
--
At the nanometer level, the world is made of rubber (с)
Аватара пользователя
Serg
Мастер
Сообщения: 21923
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5181
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

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

Сообщение Serg »

Задание/вопрос было предельно короткое и ясное. :)
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
MX_Master
Мастер
Сообщения: 7467
Зарегистрирован: 27 июн 2015, 19:45
Репутация: 3089
Настоящее имя: Михаил
Откуда: Алматы
Контактная информация:

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

Сообщение MX_Master »

Во я ламер а.. :thinking: товарищи-программисты, как в С объявить двумерный массив, расположенный по точно указанному адресу памяти?
Duhas
Мастер
Сообщения: 1949
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 284
Настоящее имя: Андрей
Откуда: Красноярск
Контактная информация:

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

Сообщение Duhas »

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

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

обращаться то как туда хочется?
Аватара пользователя
merkwurdigliebe
Мастер
Сообщения: 608
Зарегистрирован: 17 дек 2013, 22:14
Репутация: 580
Откуда: București
Контактная информация:

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

Сообщение merkwurdigliebe »

Код: Выделить всё

#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]);
}
Duhas
Мастер
Сообщения: 1949
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 284
Настоящее имя: Андрей
Откуда: Красноярск
Контактная информация:

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

Сообщение Duhas »

так то оно так, но вопрошающий тут о конкретном адресе заикается )
Аватара пользователя
merkwurdigliebe
Мастер
Сообщения: 608
Зарегистрирован: 17 дек 2013, 22:14
Репутация: 580
Откуда: București
Контактная информация:

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

Сообщение merkwurdigliebe »

ну я уж думаю он догадается маллок на конкретный адрес заменить...
Duhas
Мастер
Сообщения: 1949
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 284
Настоящее имя: Андрей
Откуда: Красноярск
Контактная информация:

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

Сообщение Duhas »

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

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

Сообщение MX_Master »

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

#include <stdint.h>

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

array[0][0] = 1; // использую вот так
Duhas
Мастер
Сообщения: 1949
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 284
Настоящее имя: Андрей
Откуда: Красноярск
Контактная информация:

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

Сообщение Duhas »

сама память уже выделена где-то ?
Аватара пользователя
MX_Master
Мастер
Сообщения: 7467
Зарегистрирован: 27 июн 2015, 19:45
Репутация: 3089
Настоящее имя: Михаил
Откуда: Алматы
Контактная информация:

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

Сообщение MX_Master »

Duhas писал(а):сама память уже выделена где-то ?
Да. Проверил. Кроме меня там никто не ковыряется :mrgreen:
Аватара пользователя
Serg
Мастер
Сообщения: 21923
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5181
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

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

Сообщение Serg »

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

И тебе как выделить, абы как или чтоб туда гарантированно никто другой не влез? :hehehe:
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Duhas
Мастер
Сообщения: 1949
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 284
Настоящее имя: Андрей
Откуда: Красноярск
Контактная информация:

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

Сообщение Duhas »

дык она замаллочена или просто решено писать вон туда ? ))
Аватара пользователя
MX_Master
Мастер
Сообщения: 7467
Зарегистрирован: 27 июн 2015, 19:45
Репутация: 3089
Настоящее имя: Михаил
Откуда: Алматы
Контактная информация:

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

Сообщение MX_Master »

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

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

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

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

Сообщение Duhas »

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

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

Сообщение MX_Master »

Андрей, общаться будут не 2 процесса промеж собой, а 2 разных процессора разной архитектуры :)
Аватара пользователя
Serg
Мастер
Сообщения: 21923
Зарегистрирован: 17 апр 2012, 14:58
Репутация: 5181
Заслуга: c781c134843e0c1a3de9
Настоящее имя: Сергей
Откуда: Москва
Контактная информация:

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

Сообщение Serg »

MX_Master писал(а):Мне в общем виде, чтобы для большинства компилеров эффект был одинаковый.
У разных компиляторов немного разные синтаксисы. В общем случае просто указателю присваиваешь конкретный адрес, но инициализировать массив начальными значениями придётся вручную.
MX_Master писал(а):Гарантированно в разнопроцессорных чипах может быть только по обоюдному согласию. Но это далеко ещё не факт. Ибо кто-то третий в новых версиях софта всегда может подумать иначе.
Вот чтобы такого не было, например чтоб стэк или куча растолстев на влезли в твою область, нужно выделять конкретный регион в памяти и сообщать о нём линкеру в соотв. конфиге.
MX_Master писал(а):Я б, канеш, воспользовался стандартным механизмом коммуникации промеж пиоцессоров, но он настолько убогий, что без слез не взглянешь...
Но он наверняка позволяет синхронизировать обращения к общей памяти, например чтобы не получилось, что один процессор пытаясь считать uint32_t не считает 2 байта от нового значения и 2 байта от старого, сунувшись туда в момент, когда другой обновляет это значение.
Я не Христос, рыбу не раздаю, но могу научить, как сделать удочку...
Аватара пользователя
MX_Master
Мастер
Сообщения: 7467
Зарегистрирован: 27 июн 2015, 19:45
Репутация: 3089
Настоящее имя: Михаил
Откуда: Алматы
Контактная информация:

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

Сообщение MX_Master »

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

В чипе есть небольшая область под spinlock'и, ею можно воспользоваться.
Ответить

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