Особенности мобильного программирования на языке Си — КиберПедия 

Семя – орган полового размножения и расселения растений: наружи у семян имеется плотный покров – кожура...

Папиллярные узоры пальцев рук - маркер спортивных способностей: дерматоглифические признаки формируются на 3-5 месяце беременности, не изменяются в течение жизни...

Особенности мобильного программирования на языке Си

2020-04-01 104
Особенности мобильного программирования на языке Си 0.00 из 5.00 0 оценок
Заказать работу

Особая роль языка программирования Си состоит в том, что он, с одной стороны, позволяет писать для UNIX-систем практически столь же эффективный код, что и языки ассемблера, а с другой, является основным средством переноса программ между UNIX-системами. Можно сказать, что Си является машинно-независимым языком ассемблера для UNIX-систем. Это делает его основным средством написания эффективных и переносимых программ для этого класса вычислительных систем. Стандартизация языка сначала Американским национальным институтом стандартов (ANSI), а затем и Международной организацией по стандартам (ISO) закрепила эту роль, распространив ее и на персональные компьютеры. Будем ссылаться на версию языка Си, определенную стандартом, как на язык ANSI C.

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

Программа на ANSI C переносима из исходной ВС в целевую, если она успешно компилируется в целевой ВС и ее работа функционально эквивалентна работе в исходной ВС.

На переносимость программы влияют особенности как аппаратного, так и программного окружения языка в исходной и в целевой ВС. Можно выделить четыре фактора, влияющих на переносимость программы:

· архитектура вычислительных систем;

· метрические ограничения компиляторов;

· алгоритмы работы компиляторов;

· особенности операционных систем.

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

Даже если программа удовлетворяет всем ограничениям ANSI C и прошла стадию компиляции в исходной ВС, может случиться, что в целевой ВС она эту стадию не пройдет из-за того, что некоторые метрические характеристики программы не удовлетворяют ограничениям, принятым в целевой ВС. Примерами таких характеристик являются: число уровней вложенностей составных операторов, операторов цикла и операторов выбора варианта; число описателей указателя, массива и функции, модифицирующих базовый тип в описании объекта; число выражений, вложенных друг в друга по круглым скобкам и т.п.

От алгоритмов работы компилятора зависит, например, порядок вычисления выражений, что влияет как на значения выражений, так и на вырабатываемый ими побочный эффект.

Наконец, семантика многих стандартных библиотечных функций (например, функций ввода/вывода) зависит от особенностей операционной системы.

Все перечисленные факторы учтены в определении ANSI C путем фиксирования неуточняемого (стандартом) поведения программ, неопределенного поведения программ и поведения программ, определяемого реализацией.

Неуточняемое поведение (unspecified behavior) - это поведение правильных программ с корректными данными в ситуациях, для которых стандарт не выдвигает никаких требований.

Неопределенное поведение (undefined behavior) - поведение (динамически) ошибочных программ с возможно некорректными данными или объектами с неопределенными значениями, для которых стандарт не выдвигает никаких требований. Диапазон неопределенного поведения может быть очень разнообразен: от полного игнорирования ситуации с непредсказуемыми результатами до поведения (во время трансляции или выполнения) в соответствии с документацией, описывающей характеристики среды (с выдачей диагностических сообщений или без таковой); возможны случаи преждевременного завершения трансляции или вычислений (с обязательной выдачей диагностического сообщения).

Поведение, определяемое реализацией (implementation-defined behavior) - поведение правильно написанной программы с правильными данными, которое зависит от характеристик реализации и которое должно быть документировано каждой реализацией.

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

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

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

Неуточняемое поведение

Не уточняются следующие вопросы:

· Метод и время инициации статических данных.

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

· Ситуация, когда выдается печатный символ, а активная позиция находится в конце строки.

· Ситуация, когда выдается символ "шаг назад", а активная позиция находится в начале строки.

· Ситуация, когда выдается символ "горизонтальная табуляция", а активная позиция находится "на" или "за" последней определенной позицией горизонтальной табуляции.

· Ситуация, когда выдается символ "вертикальная табуляция", а активная позиция находится "на" или "за" последней определенной позицией вертикальной табуляции.

Предыдущие четыре ситуации влияют на вывод текста на дисплей.

· Представление плавающих типов.

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

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

· Порядок, в котором возникают побочные эффекты.

· Порядок, в котором вычисляются параметры вызова функции и само значение этой функции.

За исключением тех случаев, когда порядок вычисления выражения зафиксирован синтаксическими правилами или указан в стандарте каким-либо другим образом (для операции вызова функции (), операций логического умножения, логического сложения, условной операции и операции перечисления выражений), порядок вычисления подвыражений и порядок возникновения побочных эффектов не уточняется. Выражение, содержащее более, чем одно вхождение одной и той же коммутативной и ассоциативной бинарной операции (*, +, &, ^, |), может свободно перегруппировываться, независимо от наличия скобок, при условии, что типы операндов или результаты от такой перегруппировки не изменятся. В переносимой программе следует избегать выражений, порядок вычисления которых существенно влияет на их значения или вырабатываемые побочные эффекты. Если же такое выражение возникает, то содержащий его оператор всегда можно разбить на эквивалентную последовательность из нескольких операторов, не содержащих подобных выражений. Например, оператор

x=f()+g();

можно заменить на последовательность операторов

y=f();

x=y+g();

или

y=g();

x=f()+y;

в зависимости от нужного порядка вызова функций f() и g().

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

· Отведение памяти под формальные параметры.

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

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

· Подробности о значении, запоминаемом в случае успешной работы функции fgetpos.

· Подробности о значении, вырабатываемом для текстового потока в случае успешной работы функции ftell.

· Порядок и взаимное расположение областей памяти, захватываемых функциями calloc, malloc и realloc.

· Какой из двух элементов, оказавшихся равными при сравнении, возвращается функцией bsearch.

· Порядок расстановки в отсортированном функцией qsort массиве двух элементов, оказавшихся равными при сравнении.

· Структура календарного времени, возвращаемого функцией time.

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

Неопределенное поведение

Поведение не определяется для следующих ситуаций:

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

· Делается попытка модифицировать строковую константу.

· Идентификаторы, которые должны обозначать одну и ту же сущность, различаются хотя бы одним символом.

· В символьной или строковой константе обнаружена неизвестная управляющая последовательность.

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

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

· Арифметическая операция неверна (например, деление на 0) или выдает результат, который нельзя представить в отведенном пространстве (например, переполнение или потеря значимости).

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

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

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

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

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

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

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

· Указатель на объект, не являющийся элементом массива, используется в операции прибавления или вычитания константы.

· Вычисляется разность указателей, относящихся к разным массивам.

· Результат выражения сдвигается на отрицательную величину или на величину, большую или равную (в битах) размеру сдвигаемого результата.

· Сравниваются указатели, относящиеся к разным составным объектам.

· Значение объекта присваивается перекрывающемуся по памяти объекту.

· Делается попытка изменить объект, описанный как константа, с помощью указателя на тип, в котором нет атрибута const.

· Объект, описанный с атрибутом volatile, указывается с помощью указателя на тип, не имеющего такого же атрибута.

· Описания объекта, имеющего внешнюю связь, в двух разных файлах или в разных областях видимости одного файла, дают этому объекту разные типы.

· Значение автоматического неинициированного объекта используется до первого присваивания.

· Используется результат работы функции, которая, однако, не возвращает никакого значения.

· Функция, обрабатывающая переменное число параметров, определяется без списка типов параметров в эллиптической нотации.

· Фактический параметр макровызова не имеет ни одной препроцессорной лексемы.

· Внутри списка параметров макровызова имеются препроцессорные лексемы, которые могут быть проинтерпретированы как директивы препроцессора.

· В результате выполнения препроцессорной операции слияния лексем (##) получается неверная препроцессорная лексема.

· Эффект, возникающий в программе при переопределении зарезервированного внешнего идентификатора.

· Параметр identifier в макровызове offset соответствует битовому полю записи.

· Фактический параметр библиотечной функции имеет неверное значение, если только поведение этой функции в подобном случае не описано явно.

· Библиотечная функция, обрабатывающая переменное число параметров, не описана.

· Для доступа к настоящей функции assert использована макродиректива #undef.

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

· Вызов функции setjmp производится в ином контексте, нежели при сравнении с целочисленным выражением из констант в переключателе или в условном операторе.

· Значение автоматического объекта, не имеющего атрибута volatile, изменилось между вызовами setjmp и longjmp.

· Функция longjmp вызывается из динамически вложенной программы обработки сигнала.

· Сигнал возникает не в результате работы функций abort или raise, а при обработке сигнала вызывается библиотечная функция, не являющаяся самой функцией signal, или со статическим объектом проделывается не присваивание ему значения статической переменной с атрибутом volatile типа sig_atomic_t.

· Параметр parmN макроопределения va_start описывается в классе регистровой памяти.

· При вызове макроимени va_arg очередного фактического параметра не оказалось.

· Тип фактического параметра из списка параметров не согласуется с типом, указанным в макровызове va_arg.

· Функция va_end вызывается без предварительного обращения к макровызову va_start.

· Из функции с переменным числом параметров, список которых был проинициирован с помощью макровызова va_start, возврат производится до вызова va_end.

· Формат в функциях fprintf и fscanf не соответствует списку фактических параметров.

· В формате функций fprintf или fscanf обнаружена неверная спецификация преобразования.

· Среди спецификаторов преобразования для спецификации, не входящей в список o, x, X, e, E, f, g и G встретился признак #.

· Фактическим параметром функции fprintf, не соответствующим преобразованиям %s и %p, является составной объект или указатель на составной объект.

· Отдельное преобразование в функции fprintf породило более 509 выходных символов.

· Фактическим параметром преобразования %p функции fscanf является значение указателя, выданное при преобразовании %p функцией fprintf во время предыдущих запусков программы.

· Результат преобразования, выполняемого функцией fscanf, не может быть представлен в объеме памяти, отведенной для него, или полученный объект имеет неподходящий тип.

· Результат преобразования строки в число с помощью функций atof, atoi или atol не может быть представлен.

· Фактический параметр функций free или realloc не совпадает с ранее полученными указателями, выработанными функциями calloc, malloc или realloс, или указывается объект, ранее уничтоженный вызовом функций free или realloc.

· Ссылка на память, освобожденную функциями free или realloc.

· При вызове из функции exit функция, зарегистрированная обращением к atexit, производит доступ к автоматическому объекту программы.

· Результат целочисленных арифметических функций (abs, div, labs или ldiv) не может быть представлен.

· Массив, в который идет запись копированием или конкатенацией, слишком мал.

· Функции memcpy, strcpy или strncpy копируют объект в перекрывающийся с ним по памяти другой объект.

· В формате функции strftime обнаружена неверная спецификация преобразования.

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

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

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


Поделиться с друзьями:

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

Папиллярные узоры пальцев рук - маркер спортивных способностей: дерматоглифические признаки формируются на 3-5 месяце беременности, не изменяются в течение жизни...

Поперечные профили набережных и береговой полосы: На городских территориях берегоукрепление проектируют с учетом технических и экономических требований, но особое значение придают эстетическим...

Индивидуальные и групповые автопоилки: для животных. Схемы и конструкции...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.057 с.