2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




На страницу Пред.  1, 2, 3, 4, 5, 6  След.
 
 Re: Сравнение двух стилей программирования
Сообщение14.12.2012, 02:51 
Аватара пользователя
Качественный код дело не простое.
С одной стороны. Хочется предусмотреть все несчастные случае и добавляешь проверки.
С другой стороны хочется писать чистый код не загромождая его проверками. И это возможно писать качественный код без проверок или с минимальным числом проверок.

И это только одна сторона качественного кода.

Арифметические операции подвержены переполнения переменных. И для устранения этого в одних языках/библиотеках применяют соглашения о автоматической конвертирование типов. В других напротив применяют длинную арифметику.

Длинные функции это плохо, но большинство из известных мне математических алгоритмов очень длинные и не красивые, как не крути.

Если ничего не делать то и качественный код не получиться. Поэтому и следует стараться как можно сильнее. Есть куча советов о том как сделать ваш код более качественным.

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

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение14.12.2012, 13:40 
ewert в сообщении #658180 писал(а):
Должен скомпилироваться по логике языка (Дельфи -- это всё-таки Паскаль). Он же заранее не знает, байт там выйдет в момент обращения, или два, или ещё сколько.

Я или схожу с ума, или реально уже все позабыл? Компилятор видит вызов процедуры с аргументом типа Integer, он знает, что формальный параметр имеет тип Byte, он знает, что автоматического преобразования из Integer в Byte нету — и прекращает трансляцию с ошибкой.

Ладно, щас поставим, посмотрим.

-- Пт дек 14, 2012 14:45:15 --

Pavia в сообщении #658193 писал(а):
С другой стороны хочется писать чистый код не загромождая его проверками. И это возможно писать качественный код без проверок или с минимальным числом проверок.

Например:
Код:
export int func(Type params);

int func(Type params) {
  return _checkFuncParams(params) ? _funcImpl(params) : -1;
}


В функции _funcImpl никаких проверок уже нет, но она не экспортируется и видна только вам, как создателю модуля.

Pavia в сообщении #658193 писал(а):
Но сейчас лично меня интересует как писать код с минимальным числом проверок входных параметров. Какие языки способствуют этому?

Любые с поддержкой исключений. Нагрузка на проверку корректности ложится не на процедуру, а на того, кто ее вызывает.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение14.12.2012, 14:10 
Joker_vD в сообщении #658276 писал(а):
он знает, что автоматического преобразования из Integer в Byte нету

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

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение14.12.2012, 14:29 
ewert в сообщении #658284 писал(а):
Ну как он может это знать,

А как сишарповский компилятор это знает? У любого выражения есть вполне определенный тип. Просто в Си/Си++/Дельфи все целые типы автоматически преобразуются друг в друга (что довольно печально).

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение14.12.2012, 17:41 
И да, я действительно ошибался, когда говорил, что
Joker_vD в сообщении #658276 писал(а):
автоматического преобразования из Integer в Byte нету

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

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение14.12.2012, 17:46 
Все эти разговоры про дебаггабал, модифайабал и реюзабал, писать функции как библиотечные и т.п. конечно очень правильны и хороши. Однако, буквально сейчас, написал 3 своих функции - аналогов printf. Которые ничего не проверяют, мизерно форматируют и шлют данные в выходной поток. А за корректностью передаваемых данных я слежу при их вызове. Казалось бы - зачем, когда эта функция написана, есть в стандартной библиотеке и вызывается с кучей вариантов входных переменных и форматирования вывода? А затем, что я вывожу данные в отладочную печать в терминалы, у меня распределенная система реального времени из нескольких МК, связанных по радиоканалу, и я потратил достаточно времени чтобы понять, что ошибки возникают не из-за неправильной логики моего кода, а просто потому что стандартный библиотечный prinf безобразно медленный (за счет своей долбаной универсальности), и не влезает в мои тайм-слоты, которые я отвожу на различные ситуации.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение14.12.2012, 19:36 
Joker_vD в сообщении #658296 писал(а):
Просто в Си/Си++/Дельфи все целые типы автоматически преобразуются друг в друга (что довольно печально).

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

-- Пт дек 14, 2012 20:49:36 --

Joker_vD в сообщении #658378 писал(а):
передать в подпрограмму байт не выйдет, передается минимум машинное слово,

Да нет, теоретически можно передать даже хоть и байт (и даже формально такие конструкции вполне встречаются), просто на практике никто этими возможностями не пользуется за их непрактичностью. Т.е. на практике между программистом и транслятором стоит некий фильтр, который предугадывает желания программиста.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение14.12.2012, 20:32 
ewert в сообщении #658424 писал(а):
Что довольно правильно. Ведь, в конце-то концов, все разумные типы просто обязаны автоматически приводиться друг к другу. Кроме неестественных ситуаций -- но это уже обязанность программиста предусмотреть эти особые случаи; ведь никто, кроме него, не сможет предугадать, когда те случаи возникнут в его конкретных задачках.

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

ewert в сообщении #658424 писал(а):
Да нет, теоретически можно передать даже хоть и байт

На x86 невозможно положить на стек ровно байт.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение14.12.2012, 21:08 
Joker_vD в сообщении #658446 писал(а):
Велика радость: нечаянно обронить три байта из четырех.
Мало чем отличается от переполнения при сложении.

Joker_vD в сообщении #658446 писал(а):
На x86 невозможно положить на стек ровно байт.
Можно, для этого не обязательно пользоваться командой push. Есть ещё зачастую более эффективная команда mov, и хороший компилятор ею пользуется, если это выгодно.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение14.12.2012, 21:20 
Joker_vD в сообщении #658446 писал(а):
да вообще неявное приведение численных типов — источник труднообнаружимых ошибок

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

В том же Паскале есть механизм приведения типов (или уж не помню, как он называется). Запросто можно написать то-нибудь типа byte(c):=i или там char(b):='&', или наоборот, и это весьма эффективно. Если, конечно, хоть изредка приходить в сознание.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение14.12.2012, 22:05 
venco в сообщении #658469 писал(а):
Мало чем отличается от переполнения при сложении.

Отличается, и сильно: переполнение приводит к установке OF, это легко отследить. А вот как узнать, что старшие три байта никто не читал?

venco в сообщении #658469 писал(а):
Можно, для этого не обязательно пользоваться командой push. Есть ещё зачастую более эффективная команда mov, и хороший компилятор ею пользуется, если это выгодно.

Как все-таки здорово, что x86 позволяет misalignment, правда? На ARM это не прокатило бы, ну так там и параметры традиционно идут в регистрах — которые отнюдь не байтовые.

ewert в сообщении #658475 писал(а):
В том же Паскале есть механизм приведения типов (или уж не помню, как он называется). Запросто можно написать то-нибудь типа byte(c):=i или там char(b):='&', или наоборот, и это весьма эффективно. Если, конечно, хоть изредка приходить в сознание.

Вот именно — есть механизм явного приведения типов (в любом языке). И используется он для двух вещей:
1) Сказать компилятору "Ты этого не знаешь, но на самом деле это значение — вот такого типа, а не того, которого ты думаешь". При этом никакого кода не генерируется, просто компилятор начинает считать, что тип у переменной другой. Пример: char *t = (char*)malloc(32 * sizeof(char));
2) Сказать компилятору "Я хочу преобразовать значение одного типа в значение другого типа". При этом компилятор вставляет код, который преобразует значение одного типа в значение другого типа. Пример: float x = 2.0; int y = (int)x;

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

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение14.12.2012, 22:11 
Joker_vD в сообщении #658495 писал(а):
venco в сообщении #658469 писал(а):
Мало чем отличается от переполнения при сложении.

Отличается, и сильно: переполнение приводит к установке OF, это легко отследить.
Это в каком языке есть такая возможность?

Joker_vD в сообщении #658495 писал(а):
venco в сообщении #658469 писал(а):
Можно, для этого не обязательно пользоваться командой push. Есть ещё зачастую более эффективная команда mov, и хороший компилятор ею пользуется, если это выгодно.

Как все-таки здорово, что x86 позволяет misalignment, правда? На ARM это не прокатило бы, ну так там и параметры традиционно идут в регистрах — которые отнюдь не байтовые.
1. Причём тут выравнивание? У байтов его нет.
2. Причём тут ARM? Вы ведь явно про x86 говорите.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение14.12.2012, 22:18 
venco в сообщении #658498 писал(а):
Это в каком языке есть такая возможность?

Ассемблер. А Java VM и .NET CLR так вообще швыряют OverflowException.

venco в сообщении #658498 писал(а):
1. Причём тут выравнивание? У байтов его нет.

Если вы положите в стек байт, то положенное вслед за ним 4-байтное слово будет либо а) невыровненным, либо б) выровненным за счет 3-байтного дополнения — т.е. вы положили все-таки не байт, а 4 байта.

venco в сообщении #658498 писал(а):
2. Причём тут ARM? Вы ведь явно про x86 говорите.

Хорошо, давайте поговорим про Itanium. Реальный пример: В Win32 API есть структура FILETIME:
Код:
typedef struct _FILETIME {
  DWORD dwLowDateTime;
  DWORD dwHighDateTime;
} FILETIME, *PFILETIME;

Она имеет размер в 8 байт, она держит младшую и старшую половины 64-разрядного целого, и некоторые товарищи обращались с ней как с __int64:
Код:
pi = (__int64*)&ft;
(*pi) += (__int64)num*datepart;


Но вот беда — такой код часто приводил к STATUS_DATATYPE_MISALIGNMENT, угадайте почему.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение14.12.2012, 22:26 
Joker_vD в сообщении #658502 писал(а):
venco в сообщении #658498 писал(а):
Это в каком языке есть такая возможность?

Ассемблер. А Java VM и .NET CLR так вообще швыряют OverflowException.
Ну так они и при преобразовании int в byte то же самое швыряют.

Joker_vD в сообщении #658502 писал(а):
venco в сообщении #658498 писал(а):
1. Причём тут выравнивание? У байтов его нет.

Если вы положите в стек байт, то положенное вслед за ним 4-байтное слово будет либо а) невыровненным, либо б) выровненным за счет 3-байтного дополнения — т.е. вы положили все-таки не байт, а 4 байта.
У вас какое-то превратное представление. Естественно, так никто не делает, ибо невыровненные данные уменьшают эффективность. А делают совсем не так - пишут ровно один байт в 4-байтовый блок в стеке. Каждый параметр выравнен как ему надо.

Joker_vD в сообщении #658502 писал(а):
venco в сообщении #658498 писал(а):
2. Причём тут ARM? Вы ведь явно про x86 говорите.

Хорошо, давайте поговорим про Itanium...
Зачем вы уводите разговор в сторону? Мы ведь про переполнение говорили, а вы всё про выравнивание.

 
 
 
 Re: Сравнение двух стилей программирования
Сообщение14.12.2012, 23:24 
Аватара пользователя
Если уж про эту задачу говорить, то Read можно внутрь AddElement затолкать и ничего передавать не надо будет и он будет единственным, заполняющим список присоединением к списку по мере надобности, а для вставки элемента в произвольное место над специальную процедуру сделать и функцию поиска элемента соответственно. Но для дата-поля динамической структуры интеджера всё равно как-то маловато будет, поэтому можно передавать ссылку на дата-структуру (или нетипизированную) и ссылку на функцию заполнения полей дата-структуры, но т.к. заголовком темы были стили программирования то уже лучше с ООП сравнивать. А на уровне оформления повторяющегося кода в виде подпрограмм в пределах одной программы надо обсуждать как в подпрограмму передаются параметры и как возвращаются.
Оптимизировать код для x86 не имеет смысла, т.к. он всё равно эмулируется и читать по 32 или 64 бита одинаково по времени что читать 8 или 16 бит, если же конечно вы не решили упаковывать 8 бит по по 4 в 32 бита.

 
 
 [ Сообщений: 82 ]  На страницу Пред.  1, 2, 3, 4, 5, 6  След.


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group