Страница 4 из 9

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

Добавлено: 13 дек 2019, 10:19
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: Замечу, что все мои выводы полностью аргументированы и подкреплены ссылками на стандарт и цитатами из него же.

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

Добавлено: 13 дек 2019, 19:26
Serg
netraider писал(а):рассуждать абсолютно бессмысленно
Именно! Ибо пример/задачка совсем о другом.

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

Добавлено: 17 дек 2019, 12:51
netraider
UAVpilot писал(а):
netraider писал(а):рассуждать абсолютно бессмысленно
Именно! Ибо пример/задачка совсем о другом.
Любой результат будет допустимым. Вот поэтому и бессмысленно. Либо же нужно изменить формулировку - "Пример/задачка содержит UB. Нужно объяснить конкретный наблюдаемый вариант (их может быть несколько)". С такой формулировкой я согласен. Только нужно понимать что поведение в случае наличия UB остается за рамками стандарта языка. Соответственно ни о каком правильном вараинте ответа не может быть и речи, т.к. "правильность" нельзя доказать.

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

Добавлено: 17 дек 2019, 23:14
Serg
Задание/вопрос было предельно короткое и ясное. :)

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

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

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

Добавлено: 18 апр 2020, 14:49
Duhas
ну в си нет как таковых двумерных массивов, вопрос только как это выглядит в коде )

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

обращаться то как туда хочется?

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

Добавлено: 18 апр 2020, 15:05
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]);
}

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

Добавлено: 18 апр 2020, 15:21
Duhas
так то оно так, но вопрошающий тут о конкретном адресе заикается )

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

Добавлено: 18 апр 2020, 15:37
merkwurdigliebe
ну я уж думаю он догадается маллок на конкретный адрес заменить...

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

Добавлено: 18 апр 2020, 15:39
Duhas
коли вопрошает - могут быть варианты ) я почему то в контексте его других постов подозреваю что он что-то желает в "условно аппаратную" часть записать ) пускай колется чего ваяет )

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

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

#include <stdint.h>

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

array[0][0] = 1; // использую вот так

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

Добавлено: 18 апр 2020, 17:56
Duhas
сама память уже выделена где-то ?

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

Добавлено: 18 апр 2020, 17:59
MX_Master
Duhas писал(а):сама память уже выделена где-то ?
Да. Проверил. Кроме меня там никто не ковыряется :mrgreen:

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

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

И тебе как выделить, абы как или чтоб туда гарантированно никто другой не влез? :hehehe:

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

Добавлено: 18 апр 2020, 18:24
Duhas
дык она замаллочена или просто решено писать вон туда ? ))

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

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

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

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

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

Добавлено: 18 апр 2020, 20:13
Duhas
я о том что стоит не просто писать в понравившийся адрес а выделить память в одном процессе и отдать указатель на нее другому.

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

Добавлено: 18 апр 2020, 20:27
MX_Master
Андрей, общаться будут не 2 процесса промеж собой, а 2 разных процессора разной архитектуры :)

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

Добавлено: 18 апр 2020, 20:51
Serg
MX_Master писал(а):Мне в общем виде, чтобы для большинства компилеров эффект был одинаковый.
У разных компиляторов немного разные синтаксисы. В общем случае просто указателю присваиваешь конкретный адрес, но инициализировать массив начальными значениями придётся вручную.
MX_Master писал(а):Гарантированно в разнопроцессорных чипах может быть только по обоюдному согласию. Но это далеко ещё не факт. Ибо кто-то третий в новых версиях софта всегда может подумать иначе.
Вот чтобы такого не было, например чтоб стэк или куча растолстев на влезли в твою область, нужно выделять конкретный регион в памяти и сообщать о нём линкеру в соотв. конфиге.
MX_Master писал(а):Я б, канеш, воспользовался стандартным механизмом коммуникации промеж пиоцессоров, но он настолько убогий, что без слез не взглянешь...
Но он наверняка позволяет синхронизировать обращения к общей памяти, например чтобы не получилось, что один процессор пытаясь считать uint32_t не считает 2 байта от нового значения и 2 байта от старого, сунувшись туда в момент, когда другой обновляет это значение.

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

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

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