Язык Си в примерах/Учимся складывать: различия между версиями

Материал из Викиучебника — открытых книг для открытого мира
Содержимое удалено Содержимое добавлено
Отмена правок до 106713 — для ctags(1) (см. Обсуждение:Язык Си в примерах#Оформление кода); →‎if: новый XML id.
Вводная дополнена «стандартной формулой»; новые XML id; →‎Примечания: {{Cite web | … | publisher = ISO/IEC | …}}.
Строка 6: Строка 6:
Давайте и мы научимся использовать компьютер для вычислений.
Давайте и мы научимся использовать компьютер для вычислений.
Начнём со сложения двух чисел.
Начнём со сложения двух чисел.

; {{Якорь2 |Дано}}: два разделенных ''пробельными символами'' [[w:Целое число |целых чисел]] (в «текстовом» десятичном представлении) на [[w:Стандартные потоки#Стандартный ввод |стандартном вводе]] программы.
; Найти: значение суммы (разности, произведения, частного от деления — если имеет смысл) этих двух чисел.
; Новые элементы языка: переменные; тип [[#double |double]]; операторы [[#& |&]], [[#* |*]], [[#? : |? :]] контекста ''выражения'' и оператор [[#if |if]] контекста ''утверждения''; макроподстановка [[#assert |assert]], функции [[#printf |printf]], [[#scanf |scanf]].


== Вариант «простой» ==
== Вариант «простой» ==
Строка 29: Строка 33:
</source>
</source>


{{Якорь |printf}}
Рассмотрим выполнение этой программы почти с ее завершения — вызова функции <code >printf</code>.<ref name="fprintf" /> Данная функция выведет целое число в десятичной форме (согласно ''указателю преобразования'' <code >%d</code>), завершая вывод [[w:Перевод строки |переводом строки]] (<code >\n</code>).
Рассмотрим выполнение этой программы почти с ее завершения — вызова функции <code >printf</code>.<ref name="fprintf" /> Данная функция выведет целое число в десятичной форме (согласно ''указателю преобразования'' <code >%d</code>), завершая вывод [[w:Перевод строки |переводом строки]] (<code >\n</code>).


Число, которое будет выведено, является результатом вычисления выражения <source lang="c" enclose="none" >a + b</source> — или же, проще говоря, — суммой значений переменных <var >a</var> и <var >b</var>.
Число, которое будет выведено, является результатом вычисления выражения <source lang="c" enclose="none" >a + b</source> — или же, проще говоря, — суммой значений переменных <var >a</var> и <var >b</var>.


{{Якорь |scanf}}
Вводимые пользователем числа помещаются в эти переменные функцией <code >scanf</code>, вызываемой в коде выше как <source lang="c" enclose="none" >scanf ("%d%d", &a, &b)</source>.<ref name="fscanf" /> Здесь, как и в <code >printf</code>, используется указатель преобразования <code >%d</code>, означающий на этот раз ''считывание'' числа в десятичной форме (возможно — предваряемого пробелами). Поскольку указатель повторен дважды, два числа будут считаны и помещены в упомянутые в аргументах две переменные <var >a</var> и <var >b</var>. (Необходимый здесь унарный оператор <code >&</code> оставим пока без внимания.)
Вводимые пользователем числа помещаются в эти переменные функцией <code >scanf</code>, вызываемой в коде выше как <source lang="c" enclose="none" >scanf ("%d%d", &a, &b)</source>.<ref name="fscanf" /> Здесь, как и в <code >printf</code>, используется указатель преобразования <code >%d</code>, означающий на этот раз ''считывание'' числа в десятичной форме (возможно — предваряемого пробелами). Поскольку указатель повторен дважды, два числа будут считаны и помещены в упомянутые в аргументах две переменные <var >a</var> и <var >b</var>. (Необходимый здесь унарный оператор <code >&</code> оставим пока без внимания.)


Строка 39: Строка 45:
В [[../Простейшая программа «Hello World» |простейшей программе]] от действий пользователя не зависело ровным счетом ничего. Каким, однако, будет результат выполнения данной программы, если ввод пользователя <em >не будет</em> начат двумя числами в десятичной форме?
В [[../Простейшая программа «Hello World» |простейшей программе]] от действий пользователя не зависело ровным счетом ничего. Каким, однако, будет результат выполнения данной программы, если ввод пользователя <em >не будет</em> начат двумя числами в десятичной форме?


{{Якорь |assert}}
Для проверки соответствия ввода пользователя требованиям программы мы ''сохраняем'' (<code >=</code>) результат выполнения <code >scanf</code> — количество успешно измененных переменных — в целочисленной переменной с именем <var >r</var> (<source lang="c" enclose="none" >int r</source>), после чего ''требуем'' равенства ее значения двум (<source lang="c" enclose="none" >assert (r == 2);</source>.)
Для проверки соответствия ввода пользователя требованиям программы мы ''сохраняем'' (<code >=</code>) результат выполнения <code >scanf</code> — количество успешно измененных переменных — в целочисленной переменной с именем <var >r</var> (<source lang="c" enclose="none" >int r</source>), после чего ''требуем'' равенства ее значения двум (<source lang="c" enclose="none" >assert (r == 2);</source>.)


Строка 47: Строка 54:
== Вариант «дробный» ==
== Вариант «дробный» ==


{{Якорь |double}}
Рассмотренную [[#Вариант «простой»|выше]] программу несложно изменить для использования [[w:Число с плавающей запятой|чисел с плавающей запятой.]]
Рассмотренную [[#Вариант «простой»|выше]] программу несложно изменить для использования [[w:Число с плавающей запятой|чисел с плавающей запятой.]]


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


{{Якорь |&}}
В некоторых случаях, однако, мы хотим получить от функции что-либо обратно. Иногда, для этого достаточно предусмотренного языком ''возвращаемого значения''. Иначе, можно отправить функции своего рода ''конверт с обратным адресом'' (один или несколько). Именно для этого — для получения ''адреса л-значения'' — служит унарный оператор <code>&</code>.
В некоторых случаях, однако, мы хотим получить от функции что-либо обратно. Иногда, для этого достаточно предусмотренного языком ''возвращаемого значения''. Иначе, можно отправить функции своего рода ''конверт с обратным адресом'' (один или несколько). Именно для этого — для получения ''адреса л-значения'' — служит унарный оператор <code>&</code>.


Строка 81: Строка 90:
Справа от оператора <code >&</code> указывается ''л-значение'' (англ. {{lang|en|lvalue}}.<ref name="lvalues et al" /> Не вдаваясь в подробности отметим, что под л-значением понимают любое выражение, которое может стоять ''слева'' от оператора присваивания <code >=</code>. В частности, л-значением является любое выражение, состоящие из имени действительной в данном контексте (англ. {{lang |en|scope}}) переменной.
Справа от оператора <code >&</code> указывается ''л-значение'' (англ. {{lang|en|lvalue}}.<ref name="lvalues et al" /> Не вдаваясь в подробности отметим, что под л-значением понимают любое выражение, которое может стоять ''слева'' от оператора присваивания <code >=</code>. В частности, л-значением является любое выражение, состоящие из имени действительной в данном контексте (англ. {{lang |en|scope}}) переменной.


{{Якорь |*}}
Для обращения к ячейки памяти по ссылке используется унарный оператор <code >*</code>. Так, выражение <source lang="c" enclose="none" >*(&a) = 1</source> полностью равнозначно <source lang="c" enclose="none" >a = 1</source>.
Для обращения к ячейки памяти по ссылке используется унарный оператор <code >*</code>. Так, выражение <source lang="c" enclose="none" >*(&a) = 1</source> полностью равнозначно <source lang="c" enclose="none" >a = 1</source>.


Строка 133: Строка 143:
== Вариант «тернарный» ==
== Вариант «тернарный» ==


{{Якорь |? :}}
Используя условный оператор контекста ''выражения'' (англ. {{lang|en|conditional operator}}), а также приняв во внимание тот факт, что <code>printf</code> проигнорирует «избыточные» аргументы (аргументы сверх количества, требуемого указателями преобразований в указанной первым аргументом строке формата), можно незначительно сократить код [[#Вариант «арифметический»|предыдущего примера]].
Используя условный оператор контекста ''выражения'' (англ. {{lang|en|conditional operator}}), а также приняв во внимание тот факт, что <code>printf</code> проигнорирует «избыточные» аргументы (аргументы сверх количества, требуемого указателями преобразований в указанной первым аргументом строке формата), можно незначительно сократить код [[#Вариант «арифметический»|предыдущего примера]].


Строка 172: Строка 183:
{{Примечания | refs =
{{Примечания | refs =
<!-- Пожалуйста поддерживайте алфавитный порядок для name. Спасибо. -->
<!-- Пожалуйста поддерживайте алфавитный порядок для name. Спасибо. -->
<ref name="assert" >{{Cite web | title = 7.2.1.1 The assert macro | url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=204 | work = WG14 N1570 Committee Draft | publisher = <!-- FIXME: ? --> | datepublished = 2011-04-12 | lang = en | accessdate = 2012-11-19}}</ref>
<ref name="assert" >{{Cite web | title = 7.2.1.1 The assert macro | url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=204 | work = WG14 N1570 Committee Draft | publisher = ISO/IEC | datepublished = 2011-04-12 | lang = en | accessdate = 2012-11-19}}</ref>
<ref name="conditional" >{{Cite web | title = 6.5.15 Conditional operator | url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=118 | work = WG14 N1570 Committee Draft | publisher = <!-- FIXME: ? --> | datepublished = 2011-04-12 | lang = en | accessdate = 2012-11-19}}</ref>
<ref name="conditional" >{{Cite web | title = 6.5.15 Conditional operator | url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=118 | work = WG14 N1570 Committee Draft | publisher = ISO/IEC | datepublished = 2011-04-12 | lang = en | accessdate = 2012-11-19}}</ref>
<ref name="fprintf" >{{Cite web | title = 7.21.6.1 The fprintf function | url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=327 | work = WG14 N1570 Committee Draft | publisher = <!-- FIXME: ? --> | datepublished = 2011-04-12 | lang = en | accessdate = 2012-11-19}}</ref>
<ref name="fprintf" >{{Cite web | title = 7.21.6.1 The fprintf function | url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=327 | work = WG14 N1570 Committee Draft | publisher = ISO/IEC | datepublished = 2011-04-12 | lang = en | accessdate = 2012-11-19}}</ref>
<ref name="fscanf" >{{Cite web | title = 7.21.6.2 The fscanf function | url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=335 | work = WG14 N1570 Committee Draft | publisher = <!-- FIXME: ? --> | datepublished = 2011-04-12 | lang = en | accessdate = 2012-11-19}}</ref>
<ref name="fscanf" >{{Cite web | title = 7.21.6.2 The fscanf function | url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=335 | work = WG14 N1570 Committee Draft | publisher = ISO/IEC | datepublished = 2011-04-12 | lang = en | accessdate = 2012-11-19}}</ref>
<ref name="if" >{{Cite web | title = 6.8.4.1 The if statement | url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=166 | work = WG14 N1570 Committee Draft | publisher = <!-- FIXME: ? --> | datepublished = 2011-04-12 | lang = en | accessdate = 2012-11-19}}</ref>
<ref name="if" >{{Cite web | title = 6.8.4.1 The if statement | url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=166 | work = WG14 N1570 Committee Draft | publisher = ISO/IEC | datepublished = 2011-04-12 | lang = en | accessdate = 2012-11-19}}</ref>
<ref name="init" >{{Cite web | title = 6.7.9 Initialization | url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=157 | work = WG14 N1570 Committee Draft | publisher = <!-- FIXME: ? --> | datepublished = 2011-04-12 | lang = en | accessdate = 2012-11-19}}</ref>
<ref name="init" >{{Cite web | title = 6.7.9 Initialization | url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=157 | work = WG14 N1570 Committee Draft | publisher = ISO/IEC | datepublished = 2011-04-12 | lang = en | accessdate = 2012-11-19}}</ref>
<ref name="lvalues et al" >{{Cite web | title = 6.3.2.1 Lvalues, arrays, and function designators | url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=72 | work = WG14 N1570 Committee Draft | publisher = <!-- FIXME: ? --> | datepublished = 2011-04-12 | lang = en | accessdate = 2012-11-19}}</ref>
<ref name="lvalues et al" >{{Cite web | title = 6.3.2.1 Lvalues, arrays, and function designators | url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=72 | work = WG14 N1570 Committee Draft | publisher = ISO/IEC | datepublished = 2011-04-12 | lang = en | accessdate = 2012-11-19}}</ref>
<ref name="stdio.h" >{{Cite web | title = 7.21 Input/output <code >stdio.h</code> | url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=314 | work = WG14 N1570 Committee Draft | publisher = <!-- FIXME: ? --> | datepublished = 2011-04-12 | lang = en | accessdate = 2012-11-19}}</ref>
<ref name="stdio.h" >{{Cite web | title = 7.21 Input/output <code >stdio.h</code> | url = http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf#page=314 | work = WG14 N1570 Committee Draft | publisher = ISO/IEC | datepublished = 2011-04-12 | lang = en | accessdate = 2012-11-19}}</ref>
}}
}}



Версия от 16:16, 21 апреля 2015

Язык Си в примерах


  1. Компиляция программ
  2. Простейшая программа «Hello World»
  3. Учимся складывать
  4. Максимум
  5. Таблица умножения
  6. ASCII-коды символов
  7. Верхний регистр
  8. Скобочки
  9. Факториал
  10. Степень числа
  11. Треугольник Паскаля
  12. Корень уравнения
  13. Система счисления
  14. Сортировка
  15. Библиотека complex
  16. Сортировка на основе qsort
  17. RPN-калькулятор
  18. RPN-калькулятор на Bison
  19. Простая грамматика
  20. Задача «Расчёт сопротивления схемы»
  21. Простая реализация конечного автомата
  22. Использование аргументов командной строки
  23. Чтение и печать без использования stdio
  24. Декодирование звукозаписи в формате ADX
  25. Другие примеры

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

Дано
два разделенных пробельными символами целых чисел (в «текстовом» десятичном представлении) на стандартном вводе программы.
Найти
значение суммы (разности, произведения, частного от деления — если имеет смысл) этих двух чисел.
Новые элементы языка
переменные; тип double; операторы &, *, ? : контекста выражения и оператор if контекста утверждения; макроподстановка assert, функции printf, scanf.

Вариант «простой»

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

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

#include <assert.h>
#include <stdio.h>

int
main ()
{
  int a, b;
  int r
    = scanf ("%d%d", &a, &b);
  assert (r == 2);
  printf ("%d\n", a + b);
  return 0;
}

Рассмотрим выполнение этой программы почти с ее завершения — вызова функции printf.[1] Данная функция выведет целое число в десятичной форме (согласно указателю преобразования %d), завершая вывод переводом строки (\n).

Число, которое будет выведено, является результатом вычисления выражения a + b — или же, проще говоря, — суммой значений переменных a и b.

Вводимые пользователем числа помещаются в эти переменные функцией scanf, вызываемой в коде выше как scanf ("%d%d", &a, &b).[2] Здесь, как и в printf, используется указатель преобразования %d, означающий на этот раз считывание числа в десятичной форме (возможно — предваряемого пробелами). Поскольку указатель повторен дважды, два числа будут считаны и помещены в упомянутые в аргументах две переменные a и b. (Необходимый здесь унарный оператор & оставим пока без внимания.)

Как и printf, функция scanf объявлена в заголовке (англ. header) stdio.h.[3]

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

Для проверки соответствия ввода пользователя требованиям программы мы сохраняем (=) результат выполнения scanf — количество успешно измененных переменных — в целочисленной переменной с именем r (int r), после чего требуем равенства ее значения двум (assert (r == 2);.)

Действие макроподстановки assert заключается в вычислении выражения, переданного ей первым (и единственным) аргументом и аварийном завершении программы в случае, если полученное значение — ноль («логическая ложь».)[4]

Наконец, в самом начале функции main определены (помимо упомянутой уже r) целочисленные переменные a и b. Их значение в начале выполнения функции main может быть произвольным,[5] но после успешного (что проверяется использованием assert) завершения scanf они будут содержать два числа, которые удалось последовательно считать со стандартного ввода.

Вариант «дробный»

Рассмотренную выше программу несложно изменить для использования чисел с плавающей запятой.

#include <assert.h>
#include <stdio.h>

int
main ()
{
  double a, b;
  int r
    = scanf ("%lg%lg", &a, &b);
  assert (r == 2);
  printf ("%lg\n", a + b);
  return 0;
}

Как видно, в этом случае изменяются лишь тип переменных a, b (intdouble) и указатели преобразований (%d%lg.)

Здесь следует отметить, что в случае scanf совершенно идентично будут действовать указатели преобразований %lg, %lf и %le. Напротив, в случае printf не будет разницы между %lg и %g. Причины такого поведения мы также пока оставим без внимания.

Желающим изучить использование других числовых типов в этой задаче предлагается обратиться к разделу «Числовые типы» приложения.

Л-значения и ссылки

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

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

Так, запись &a означает адрес ячейки памяти, выделенной для хранения значения переменной a, или же, проще, — ссылка (англ. reference) на переменную a.

Справа от оператора & указывается л-значение (англ. lvalue.[6] Не вдаваясь в подробности отметим, что под л-значением понимают любое выражение, которое может стоять слева от оператора присваивания =. В частности, л-значением является любое выражение, состоящие из имени действительной в данном контексте (англ. scope) переменной.

Для обращения к ячейки памяти по ссылке используется унарный оператор *. Так, выражение *(&a) = 1 полностью равнозначно a = 1.

Вариант «арифметический»

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

#include <assert.h>
#include <stdio.h>

int
main ()
{
  double a, b;
  int r
    = scanf ("%lg%lg", &a, &b);
  assert (r == 2);
  if (b != 0) {
    printf (("a + b = %lg\n"
             "a - b = %lg\n"
             "a * b = %lg\n"
             "a / b = %lg\n"),
            a + b, a - b, a * b, a / b);
  } else {
    printf (("a + b = %lg\n"
             "a - b = %lg\n"
             "a * b = %lg\n"),
            a + b, a - b, a * b);
  }
  return 0;
}

В этой программе нам потребовался условный оператор контекста утверждения (англ. if statement) — один из четырех (наряду с &&, || и ? :) условных операторов языка. Его синтаксис:[7]

if (выражение)
  тело-если-истинно

if (выражение)
  тело-если-истинно
else
  тело-если-ложно

Где тело-если-истинно и тело-если-ложно могут быть (каждый) единственным утверждением (завершаемым ;), или же, как в примере выше, — { }-блоком.

В случае, если результат вычисления выражения — истина (другими словами — отличен от 0), выполняется тело-если-истинно; в противном случае (и если используется else) — тело-если-ложно.

Заметьте, что каждое простое утверждение (англ. statement) завершается точкой с запятой. Одна из самых популярных синтаксических ошибок начинающих программистов — не ставить точку c запятой после утверждений.

Вариант «тернарный»

Используя условный оператор контекста выражения (англ. conditional operator), а также приняв во внимание тот факт, что printf проигнорирует «избыточные» аргументы (аргументы сверх количества, требуемого указателями преобразований в указанной первым аргументом строке формата), можно незначительно сократить код предыдущего примера.

#include <assert.h>
#include <stdio.h>

int
main ()
{
  double a, b;
  int r
    = scanf ("%lg%lg", &a, &b);
  assert (r == 2);
  printf ((b != 0
           ? ("a + b = %lg\n"
              "a - b = %lg\n"
              "a * b = %lg\n"
              "a / b = %lg\n")
	   : ("a + b = %lg\n"
              "a - b = %lg\n"
              "a * b = %lg\n")),
          a + b, a - b, a * b,
	  (b != 0 ? a / b : 42));
  return 0;
}

В этом варианте, код вновь содержит те же самые строковые константы, что и в предыдущем, однако используется лишь один вызов функции printf — первым аргументом которой (в зависимости от значения переменной b) окажется одна из этих констант.

Число 42, которое передается printf пятым аргументом в случае нулевого значения b, может быть произвольным. Поскольку в этом случае функция printf получает строку формата лишь с тремя указателями формата, фактически использованы будут лишь аргументы с первого (формат) по четвертый (произведение a и b).

Общий синтаксис тернарного оператора ? : следующий:[8]

выражение ? если-истинно : если-ложно

Где выражение вычисляется первым, после чего, если оно истинно (отлично от 0), вычисляется — и принимается результатом оператора в целом — выражение если-истинно; в противном случае — если-ложно.

Примечания

  1. 7.21.6.1 The fprintf function(англ.) WG14 N1570 Committee Draft. ISO/IEC (2011-04-12). Проверено 2012-11-19 г.
  2. 7.21.6.2 The fscanf function(англ.) WG14 N1570 Committee Draft. ISO/IEC (2011-04-12). Проверено 2012-11-19 г.
  3. 7.21 Input/output stdio.h(англ.) WG14 N1570 Committee Draft. ISO/IEC (2011-04-12). Проверено 2012-11-19 г.
  4. 7.2.1.1 The assert macro(англ.) WG14 N1570 Committee Draft. ISO/IEC (2011-04-12). Проверено 2012-11-19 г.
  5. 6.7.9 Initialization(англ.) WG14 N1570 Committee Draft. ISO/IEC (2011-04-12). Проверено 2012-11-19 г.
  6. 6.3.2.1 Lvalues, arrays, and function designators(англ.) WG14 N1570 Committee Draft. ISO/IEC (2011-04-12). Проверено 2012-11-19 г.
  7. 6.8.4.1 The if statement(англ.) WG14 N1570 Committee Draft. ISO/IEC (2011-04-12). Проверено 2012-11-19 г.
  8. 6.5.15 Conditional operator(англ.) WG14 N1570 Committee Draft. ISO/IEC (2011-04-12). Проверено 2012-11-19 г.