На прошлом занятии мы начали знакомство с языком C, а также написали первую программу, которую затем успешно запустили на выполнение.
В данной программе была использована функция printf, которая выводит строку в устройство стандартного вывода (в нашем случае монитор ПК).
Функция printf «умеет» не только выводить строку, но также она «понимает» форматирование данных, причём там не так всё просто, поэтому данная тема достойна отдельного разговора. Для этого существуют различные модификаторы. Они существуют для преобразования в строчный вид данных различного типа. Также есть модификаторы для другого назначения — для выравнивания строк, для заполнения строки определёнными символами, а также для некоторых других целей.
Мы сегодня с вами остановимся на модификаторах первого типа, которые служат для преобразования данных того или иного типа в строку, что нам на первом этапе, да и не только на первом, будет очень необходимо для того, чтобы те результаты, которые мы получаем в процессе программы и которые могут быть совершенно разных типов, мы могли видеть на своих мониторах или в своей консоли. Какие бывают типы данных, мы подробно познакомимся в более поздних уроках, а сегодня мы попробуем именно вывести значения различных типов на экран, не сильно вдаваясь в разнообразие этих типов, а также не объявляя переменные данных типов заранее.
Для этого мы напишем ещё одну программу, для начала создав для неё отдельный каталог (или папку) на диске с именем MYPROG02.
Затем мы зайдём в данный каталог и скопируем туда файл main.c из папки с программой прошлого занятия MYPROG01.
Далее мы откроем наш файл в текстовом редакторе и добавим туда до вызова функции printf ещё один вызов данной функции с выводом ещё одной строки
1 2 3 4 |
int main() { printf("String: "); printf("Hello, World!!!\r\n"); |
Неактивные строки в коде выше, это строки, которые не изменились. Я их буду выводить для того, чтобы вы не путались, куда именно (в какое место программы) мы вставляем код.
Перед нашей строкой Hello World мы добавили объяснение типа данных, которые мы выводим. Мы выводим именно строку.
В вызов функции printf, которая выводит строку Hello World мы также внесём изменение. Строка теперь не будет полностью прописана, а будет использован модификатор, который будет вставлять строку, находящуюся во втором входном аргументе функции, в строку, которую мы выводим. Хоть и получается тавтология, но так нагляднее будет
printf("%s\r\n","Hello, World!!!");
Модификатор %s подставляет вместо себя результат второго параметра функции строкового типа, в нашем случае строку «Hello, World!!!«.
Посмотрим таблицу различных таких модификаторов типа данных
%с | Символ типа char |
%d | Десятичное число целого типа со знаком |
%i | Десятичное число целого типа со знаком |
%е | Научная нотация (е нижнего регистра) |
%Е | Научная нотация (Е верхнего регистра) |
%f | Десятичное число с плавающей точкой |
%g | Использует код %е или %f — тот из них, который короче (при использовании %g используется е нижнего регистра) |
%G | Использует код %Е или %f — тот из них, который короче (при использовании %G используется Е верхнего регистра) |
%о | Восьмеричное целое число без знака |
%s | Строка символов |
%u | Десятичное число целого типа без знака |
%х | Шестнадцатиричное целое число без знака (буквы нижнего регистра) |
%Х | Шестнадцатиричное целое число без знака (буквы верхнего регистра) |
%р | Выводит на экран значение указателя |
%n | Ассоциированный аргумент — это указатель на переменную целого типа, в которую помещено количество символов, записанных на данный момент |
%% | Выводит символ % |
Как видим, таких модификаторов много, можно поначалу и запутаться. Мы не будем их сегодня пробовать все, испытаем лишь несколько, которые, на мой взгляд, вскоре нам обязательно могут потребоваться. Также если потребуются другие в дальнейшем, тогда мы их и изучим, чтобы лишним сейчас не забивать наши головы. Собирать код мы будем поэтапно, не в один проход, чтобы лучше видеть, на каком этапе у нас будут ошибки или предупреждения. Только каждую команду мы теперь вводить не будем. Создадим в нашей папке с программой (а так как уже в папке у нас начинает много чего кроме программы набираться, мы уже смело её содержимое можем называть проектом) командный файл. Их ещё называют bat-файлами. Мы создадим файл с расширением cmd, так как начиная с Windows версии 7 это как-то больше принято. Файлу мы дадим говорящее название build.cmd, так как мы будем собирать в нём проект, следующего содержания
1 2 3 4 |
gcc -Wall -E main.c -o main.i gcc -Wall -S main.i -o main.s gcc -Wall -c main.c gcc -Wall main.o -o myprog02 |
Ключ -Wall означает, что мы выводим все предупреждения по ходу сборки программы.
Откроем командную строку, находясь в нашем каталоге и введём команду build
Мы не видим никаких ошибок и предупреждений, поэтому скорее всего, у нас всё собралось.
Посмотрим содержимое нашего каталога
Все файлы появились.
Вернёмся в командную строку и проверим работоспособность нашей программы
Всё отлично!
Пусть bat-файл — это далеко не файл сценария Makefile, до которого мы тоже непременно доберёмся, но тем не менее он очень сильно облегчил нам работу по сборке исполняемого файла, так как нам не приходится теперь вводить 4 команды. Теперь когда у нас накопилось 4 файла, кроме файла с исходным кодом, мы можем их также удалить одной командой. Пропишем её в ещё один созданный файл clean.cmd следующего содержания
1 2 |
@echo off del /Q *.o *.i *.s *.exe |
Верхняя команда экранирует вывод в консоль самих команд, находящихся далее в файле, а ключ /Q подавит запрос об удалении файла, то есть файл удалится без спроса. Причём в параметрах команды del мы используем не имена файлов, а только расширения, поэтому, если в каталоге встретятся файлы с любыми именами, но с указанными в параметрах расширениями, то они все удалятся. Это позволит нам в дальнейшем удалять несколько различных файлах, когда мы будем исходный код писать не в одном, а в нескольких файлах.
Введём команду в нашей командной строке
После выполнения команды мы видим, что в нашем каталоге теперь нет ничего лишнего, в том числе и исполняемого файла
В дальнейшем мы, возможно, сделаем отдельный командный файл, который не будет удалять исполняемый файл, а только объектные, ассемблерные и препроцессорные файлы, а, возможно, будем использовать параметры командной строки. Но пока нам этого не нужно.
Вернёмся, наконец-то, в наш исходный код и попробуем вывести данные какого-нибудь другого типа в нашу консоль.
Для этого добавим следующий код в нашу функцию main()
1 2 3 |
printf("%s\r\n","Hello, World!!!"); printf("Char: "); printf("%c\r\n",131); |
С помощью модификатора %c мы выводим символ с кодом 131. Если Windows использует кириллицу в кодировке, то это должна получиться буква 'Г' судя по таблице ASCII. Сохраним наш файл с кодом, соберём наш код с помощью команды build и запустим нашу программу на выполнение. Посмотрим результат работы программы
Отлично! У нас вывелся символ.
Добавим следующий код, который нам должен будет вывести значение целого 32-битного знакового типа с помощью использования модификатора %d
1 2 3 |
printf("%c\r\n",131); printf("Signed integer: "); printf("%d\r\n",3000000000); |
32-битное знаковое целое число — это число в диапазоне от -231 до 231-1 или от -2147483648 до 2147483647.
Так как предложенное во втором параметре число не входит в данный диапазон (я специально такое написал), то оно будет преобразовано в знаковый тип.
Соберём код и увидим, что на двух этапах у нас будет предупреждение (это типа ошибка, но как-бы допустимая)
Запустим нашу программу. Результат окажется вот таким
Произошло неявное (автоматическое) преобразование типа из беззнакового в знаковый. Если преобразовать данное число в шестнадцатеричный вид, а также исходное число, которое мы пытались вывести, результат будет один и тот же.
Теперь попробуем вывести то же число, используя модификатор %u
1 2 3 |
printf("%d\r\n",3000000000); printf("Unigned integer: "); printf("%u\r\n",3000000000); |
Число теперь отобразится в неизменном виде, так как беззнаковое 32-битное целое находится в диапазоне от 0 до 4294967295, хотя предупреждения все равно будут и в случае использования и этого модификатора
Попробуем вывести с помощью соответствующих модификаторов данные следующего типа — беззнакового и знакового 16-битного целого, используя такие же способы
1 2 3 4 5 |
printf("%u\r\n",3000000000); printf("Signed short: "); printf("%hd\r\n",40000); printf("Unsigned short: "); printf("%hu\r\n",40000); |
Соберём код, запустим нашу программу и посмотрим результат в консоли
Теперь подобным образом попробуем вывести, наоборот, большие, 64-битные числа в нашу консоль с помощью следующего кода
1 2 3 4 5 |
printf("%hu\r\n",40000); printf("Signed long: "); printf("%I64d\r\n",18446744073709551615); printf("Unsigned long: "); printf("%llu\r\n",18446744073709551615); |
Получим вот такой результат
А теперь попробуем вывести дробные числа с плавающей точкой (или как их тип ещё называют «вещественный тип») типа float и double (по данным форматам у нас будет ещё разговор, так как не всегда результат различных операций и процессов бывает целым)
1 2 3 4 5 |
printf("%llu\r\n",18446744073709551615); printf("Float: "); printf("%f\r\n",12.456f); printf("Double: "); printf("%lf\r\n",12345.67891); |
Результат будет следующий:
Вывод числа пока у нас не совсем красивый, присутствуют лишние нули, но зато он есть. До регулировки количества цифр после точки, а также до приведения формата вывода к определённой ширине и также его выравнивание по определённой стороне, мы ещё доберёмся.
Осталось нам ещё посмотреть, как выводится число в шестнадцатеричном виде. Число мы зададим в десятичном, пусть функция сама его преобразует в шестнадцатеричный вид
1 2 3 |
printf("%lf\r\n",12345.67891); printf("Hex: "); printf("0x%llX\r\n",3000000000); |
Посмотрим результат вывода в консоль, не обращая пока никакого внимание на предупреждения при сборке нашего кода
Можете проверить на калькуляторе, результат правильный.
Таким образом, в данном занятии мы научились пользоваться модификаторами типов данных, что позволило нам осуществить вывод данных различных типов в консоль и в дальнейшем позволит отслеживать работу наших программ, выводя в консоль те или иные результаты вычислений.
Всех благодарю за внимание!
Предыдущий урок Программирование на C Следующий урок
Смотреть ВИДЕОУРОК (нажмите на картинку)
А можно выводить например в COM порт, а не на монитор?
Пока речь не об этом. Мы пока учим язык. Поэтому не важно куда выводить, лишь бы результат был виден, чтобы оценить наши действия.
Спасибо за уроки! Смотрю Ваши уроки по AVR и по языку С до STM еще не дорос.)
Вопрос в консоли невыводит кирилицу (непонятные символы вместо нее). Кодировка в Notepad++ стоит UTF-8. Что можно сделать?
И еще подскажите как учить английский язык с прицелом на программирование и чтение даташитов?
Гусев Сергей
Откуда у Вас кириллица?
Мы же ничего на ней не пишем в bat (cmd) файле.
А вообще по умолчанию в консоли не UTF, там 866.
Узнать можно посредством команды chcp.
Чтобы переключить на UTF, даём команду
chcp 65001
Спасибо.
Я пытаюсь дополнительно свои программки писать. И вот вывожу шапку таблицы в консоль, а там вместо заголовка непонятные символы.
Вечером попробую команду chcp 65001.
У меня не стирает exe file, нет прав доступа из-за этого муторно пересобирать проект, может подскажите в какую сторону капать. Спасибо
Здравствуйте! При создании файла build вы компилируете исходный файл, а должны ассемблерный, судя по логике рассуждений. Могу быть не прав, если да, то прошу объяснить почему.
Получилось все, кроме «Теперь подобным образом попробуем вывести, наоборот, большие, 64-битные числа в нашу консоль с помощью следующего кода»
printf(«Signed long: «);
printf(«%I64d\r\n»,18446744073709551615);
printf(«Unsigned long: «);
printf(«%llu\r\n»,18446744073709551615);
Выводится:
Signed long: 40000
Unsigned long: 40000
а не то, что показано в уроке.
было то же самое
Разобрался в чем дело. Можно сказать косяк в уроке: чтобы компилятор не коцал большие цифры, надо в конце дописывать ULL
так должно быть — 18446744073709551615ULL
«Это позволит нам в дальнейшем удалять несколько различных файлах»
опечатка в последнем слове.
В build.cmd третью строчку пришлось заменить на
C:\MinGW\bin\gcc -c C:\test.s -o C:test.o
Я до сих пор методом тыка подставляю адреса и аргументы если кто-то сжалится и скинет ссылку на доки буду признателен.
Спасибо за уроки.
Подскажите пожалуйста как создать командный файл в Ubuntu?
Спасибо