Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Inline unsigned __int64 sum(unsigned __int64 a, unsigned __int64 b)




Inline __int64 sum(__int64 a, __int64 b)

Inline double sum(double a, double b)

Inline unsigned sum(unsigned a, unsigned b)

Else

If (div(b, a, res, rem))

Else

return false;

}

//-----------------------------------

int main()

{

int a = 5, b = 10, res, rem;

printf("%i + %i = %i\n%i + %i = %i\n", a, b, sum(a, b), 10, -10, sum(10, -10));

printf("%i / %i = %i + %i\n", b, a, res, rem);

return 0;

}

 

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

 

bool div(int a, int b, int *res, int *rem)

{

if (b!= 0)

{

*res = a / b;

*rem = a % b;

return true;

}

return false;

}

 

Значок * в заголовке этой функции означает, что описывается указатель на значение типа int. В теле функции операция * означает разименование, т.е. доступ к значению, которое хранится по указанному адресу (в данном случае - для его модификации).

Вызов в основной программе в этом случае выглядел бы следующим образом:

if (div(b, a, &res, &rem))

printf("%i / %i = %i + %i\n", b, a, res, rem);

 

Т.е. при передаче фактических параметров вместо формальных, которые являются указателями, приходится использовать операцию & для получения их адреса.

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

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

 

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

 

#include <stdio.h>

inline sum(int a, int b)

{

return a + b;

}

//--------------------------------

{

return a + b;

}

//--------------------------------

{

return a + b;

}

//--------------------------------

{

return a + b;

}

//--------------------------------

{

return a + b;

}

//--------------------------------

main()

{

printf("%i + %i = %i\n", 10, 5, sum(10, 5));

printf("%u + %u = %u\n", 4000000000, 20, sum(4000000000, 20));

printf("%6.4f + %6.4f = %f6.4\n", 10.234, 5.545, sum(10.234, 5.545));

printf("%I64i + %I64i = %I64i\n", __int64(40000000000), __int64(20), sum(__int64(40000000000), __int64(20)));

printf("%I64u + %I64u = %I64u\n", unsigned __int64(8000000000000000000), unsigned __int64(20), sum(unsigned __int64(8000000000000000000), unsigned __int64(20)));

return 0;

}

 

Следует отметить, что:

1. Если тип возвращаемого значения функции int, то при описании заголовка его можно не указывать.

2. В этом примере все 5 функций суммирования имеют одинаковые имена, но различные типы аргументов. Компилятор допускает такую ситуацию, которая называется перегрузка (overloading) функций. Для того, чтобы компилятор смог отличить одну функцию от другой, необходимо выполнение хотя бы одно из следующих условий:

- количество аргументов у функций было различным;

- типы аргументов (хотя бы у одного для каждой функции) отличались друг от друга;

- присутствие или отсутствие у функции признака переменного числа аргументов (запятая в конце перечня аргументов или запятая и …).

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

4. В случаях, когда компилятор неспособен автоматически определить тип выражения (использование в примере констант типа __int64 и unsigned __int64) необходимо применить явное приведение типа.

5. Для констант типа __int64 и unsigned __int64 всегда необходимо выполнять явное приведение типа, т.к. целочисленная константа по умолчанию считается типа int или unsigned int.

 

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

 

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

 

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

 

#include <stdio.h>

#define sum_macro(a, b)\

(a) + (b)

//------------------------------

template <class T> inline T sum(T a, T b)

{

return a + b;

}

//------------------------------

main()

{

printf("%i + %i = %i\n", 10, 5, sum_macro(10, 5));

printf("%i + %i = %i\n\n", 10, 5, sum(10, 5));

printf("%u + %u = %u\n", 4000000000, 20, sum(unsigned(4000000000), unsigned(20)));

printf("%u + %u = %u\n\n", 4000000000, 20, sum_macro(4000000000, 20));

printf("%6.4f + %6.4f = %f6.4\n", 10.234, 5.545, sum(10.234, 5.545));

printf("%6.4f + %6.4f = %f6.4\n\n", 10.234, 5.545, sum_macro(10.234, 5.545));

printf("%I64i + %I64i = %I64i\n", __int64(40000000000), __int64(20), sum(__int64(40000000000), __int64(20)));

printf("%I64i + %I64i = %I64i\n\n", __int64(40000000000), __int64(20), sum_macro(__int64(40000000000), 20));

printf("%I64u + %I64u = %I64u\n", unsigned __int64(8000000000000000000), unsigned __int64(20), sum(unsigned __int64(8000000000000000000), unsigned __int64(20)));

printf("%I64u + %I64u = %I64u\n\n", unsigned __int64(8000000000000000000), unsigned __int64(20), sum_macro(unsigned __int64(8000000000000000000), 20));

return 0;

}

 

Следует отметить, что:

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

2. Символ \ в конце первой строки макроопределения означает перенос на другую строку.

3. Тело макроопределения будет подставлено в точку вызова после подстановки в него аргументов макроопределения.

4. При передаче выражения в качестве аргумента оно не будет вычислено, его вычисление будет происходить после подстановки макроопределения в точку вызова. Поэтому, во избежание неправильного вычисления выражений, рекомендуется в теле макроопределения его аргументы ВСЕГДА брать в скобки.

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

6. Генерация исполнимого кода функции-шаблона происходит ТОЛЬКО после вызова этой функции в коде программы.

7. При описании функции-шаблона сначала используется ключевое слово template, после которого в <> записывается перечень абстрактных типов данных в виде: class имя_типа1, …, class имя_типаN (в примере class T). При этом вместо ключевого слова class можно использовать ключевое слово typename. Под абстрактными типами данных подразумеваются типы аргументов (локальных переменных), которые будут использованы при генерации кода функции-шаблона. Эти абстрактные типы, как правило, автоматически определяются компилятором на основании типов данных аргументов.

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

 

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

 

Пример 7. Использование значений по умолчанию для аргументов функций.

float func_sum_and_out(float a, float b, int precision = 4)

{

float res = a + b;

printf(”%7.*f”, precision, res);

return res;

}

В данном примере аргументу precision присвоено значение по умолчанию 4. Следует отметить, что если для какого-либо аргумента задано значение по умолчанию, то всем остальным аргументам, которые следуют за ним, значения по умолчанию также должны быть заданы. При вызове этой функции можно передавать как 2 фактических параметра (числа для суммирования), так и 3 - явно указывая количество знаков после десятичной точки при выводе.

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

 

 

Задание

 

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

 

#define NLen 77

typedef char NumberType[NLen];

 




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


Дата добавления: 2017-01-14; Просмотров: 843; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.038 сек.