производительности, надежности, весу и т
%PDF-1.5 % 1 0 obj > endobj 4 0 obj /ModDate (D:20150422140352+03’00’) /Producer /Title >> endobj 2 0 obj > stream application/pdf








НОУ ИНТУИТ | Лекция | Основы языка Си: структура Си-программы, базовые типы и конструирование новых типов, операции и выражения
< Лекция 12 || Лекция 8: 1234567
Аннотация: Лекция посвящена введению в язык Си. Объясняются общие принципы построения Си-программы: разбиение проекта на h- и c-файлы, т.е. разделение интерфейса и реализации, использование препроцессора. Приводятся базовые типы языка Си, конструкции массива и указателя, позволяющие строить новые типы, а также модификаторы типов. Рассматриваются всевозможные операции и выражения языка Си.
Ключевые слова: Си, Java, указатель, адрес, массив, программа, контроль, операционная система, API, application program, interface, компилятор, слово, оператор DEFINE, файл, прототип функции, имя функции, константы, переменная, представление, standard input, препроцессор, директива, символическое имя, понимание текста, функция, алгоритм, значение, аргумент, вещественное число, вычисленное значение, вызов функции, стандартный поток вывода, логический тип, класс, тело оператора, специальный тип данных, volatility, Intel 80286, операции, сложение, умножение, оператор присваивания, префиксные операции, сумма элементов массива, аргумент операции, эквивалентное выражение, type cast, неявное преобразование
Основы языка Си
Первоначально язык Си задумывался как заменитель Ассемблера
для написания операционных систем. Поскольку Си — это язык
высокого уровня, не зависящий от конкретной архитектуры, текст
операционной системы оказывался легко переносимым с одной платформы на
другую. Первой операционной системой, написанной практически целиком на
Си, была система Unix. В настоящее время почти все используемые операционные системы написаны на Си. Кроме того, средства программирования, которые операционная система
предоставляет разработчикам прикладных программ (так называемый API —
Application Program Interface), — это наборы системных функций на языке Си.
Тем не менее, область применения языка Си не ограничилась разработкой операционных систем. Язык Си оказался очень удобен в программах обработки текстов и изображений, в научных и инженерных расчетах. Объектно-ориентированные языки на основе Си отлично подходят для программирования в оконных средах.
В данном разделе будут приведены лишь основные понятия языка
Си (и частично C++). Это не заменяет чтения полного учебника по
Си или C++, например, книг [6] и [8].
Мы будем использовать компилятор C++ вместо Cи. Дело в том, что язык Си почти целиком входит в C++, т.е. нормальная программа, написанная на Си, является корректной C++ программой. Слово «нормальная» означает, что она не содержит неудачных конструкций, оставшихся от ранних версий Си и не используемых в настоящее время. Компилятор C++ предпочтительнее, чем компилятор Си, т.к. он имеет более строгий контроль ошибок. Кроме того, некоторые конструкции C++, не связанные с объектно-ориентированным программированием, очень удобны и фактически являются улучшением языка Си. Это, прежде всего, комментарии //, возможность описывать локальные переменные в любой точке программы, а не только в начале блока, и также задание констант без использования оператора #define препроцесора. Мы будем использовать эти возможности C++, оставаясь по существу в рамках языка Си.
Структура Си-программы
intuit.ru/2010/edi»>Любая достаточно большая программа на Си (программисты используют термин проект ) состоит из файлов. Файлы транслируются Си-компилятором независимо друг от друга и затем объединяются программой-построителем задач, в результате чего создается файл с программой, готовой к выполнению. Файлы, содержащие тексты Си-программы, называются исходными.В языке Си исходные файлы бывают двух типов:
- заголовочные, или h-файлы;
- файлы реализации, или Cи-файлы.
Имена заголовочных файлов имеют расширение » .h «. Имена файлов реализации имеют расширения » .c » для языка Си и » .cpp «, » .cxx » или » .cc » для языка C++.
К сожалению, в отличие от языка Си, программисты не сумели договориться о едином расширении имен для файлов, содержащих программы на C++. Мы будем использовать расширение » .h » для заголовочных файлов и расширение » .cpp » для файлов реализации.
Заголовочные файлы содержат только описания. Прежде всего, это прототипы функций. Прототип функции описывает имя функции, тип возвращаемого значения, число и типы ее аргументов. Сам текст функции в h-файле не содержится. Также в h-файлах описываются имена и типы внешних переменных, константы, новые типы, структуры и т.п. В общем, h-файлы содержат лишь интерфейсы, т.е. информацию, необходимую для использования программ, уже написанных другими программистами (или тем же программистом раньше). Заголовочные файлы лишь сообщают информацию о других программах. При трансляции заголовочных файлов, как правило, никакие объекты не создаются. Например, в заголовочном файле нельзя определить глобальную переменную. Строка описания
int x;
определяющая целочисленную переменную x, является ошибкой. Вместо этого следует использовать описание
extern int x;
означающее, что переменная x определена где-то в файле реализации (в каком — неизвестно). Слово extern (внешняя) лишь сообщает информацию о внешней переменной, но не определяет эту переменную.
Файлы реализации, или Cи-файлы, содержат тексты функций и определения глобальных переменных. Говоря упрощенно, Си-файлы содержат сами программы, а h-файлы — лишь информацию о программах.
Представление исходных текстов в виде заголовочных файлов и файлов реализации необходимо для создания больших проектов, имеющих модульную структуру. Заголовочные файлы служат для передачи информации между модулями. Файлы реализации — это отдельные модули, которые разрабатываются и транслируются независимо друг от друга и объединяются при создании выполняемой программы.
intuit.ru/2010/edi»>Файлы реализации могут подключать описания, содержащиеся в заголовочных файлах. Сами заголовочные файлы также могут использовать другие заголовочные файлы. Заголовочный файл подключается с помощью директивы препроцессора #include. Например, описания стандартных функций ввода-вывода включаются с помощью строки#include <stdio.h>
(stdio — от слов standard input/output). Имя h-файла записывается в угловых скобках, если этот h-файл является частью стандартной Си-библиотеки и расположен в одном из системных каталогов. Имена h-файлов, созданных самим программистом в рамках разрабатываемого проекта и расположенных в текущем каталоге, указываются в двойных кавычках, например,
#include "abcd.h"
Препроцессор — это программа предварительной обработки текста
непосредственно перед трансляцией. Команды препроцессора называются директивами. Директивы препроцессора содержат символ диез # в начале
строки. Препроцессор используется в основном для подключения h-файлов.
В Си также очень часто используется директива #define для задания
символических имен констант. Так, строка
#define PI 3.14159265
задает символическое имя PI для константы 3.14159265. После этого имя PI можно использовать вместо числового значения. Препроцессор находит все вхождения слова PI в текст и заменяет их на константу. Таким образом, препроцессор осуществляет подмену одного текста другим. Необходимость использования препроцессора всегда свидетельствует о недостаточной выразительности языка. Так, в любом Ассемблере средства препроцессирования используются довольно интенсивно. В Си по возможности следует избегать чрезмерного увлечения командами препроцессора — это затрудняет понимание текста программы и зачастую ведет к трудно исправляемым ошибкам. В C++ можно обойтись без использования директив #define для задания констант. Например, в C++ константу PI можно задать с помощью нормального описания
const double PI = 3.14159265;
Это является одним из аргументов в пользу применения компилятора C++ вместо Си даже при трансляции программ, не содержащих конструкции класса.
Дальше >>
< Лекция 12 || Лекция 8: 1234567
Указатели и индексы в сборке Intel 8086
спросил
Изменено 12 лет, 11 месяцев назад
Просмотрено 4к раз
У меня есть указатель на массив, DI.
Можно ли перейти к значению, на которое указывает как DI, так и другой указатель?
например:
mov bl,1 мов бх, 10 вкл [ди+бл] вкл [ди+ч]
И, кстати, существует ли однострочный код операции для замены значений двух регистров? (в моем случае BX и BP?)
- указатели
- сборка
- intel
- индексация
- x86-16
Для 16-битных программ поддерживается только адресация формы:
[BX+SI ] [БХ+ДИ] [БП+СИ] [БП+И] [СИ] [ДИ] [БП] [БХ]
Каждый из них может включать 8- или 16-битное постоянное смещение.
(Источник: Руководство разработчика Intel, том 2A, стр. 38)
Проблема с приведенным примером заключается в том, что bl
и bh
являются восьмибитными регистрами и не могут использоваться в качестве базового указателя. Однако, если вы установите bx
на желаемое значение, тогда inc [di+bx]
(с подходящим спецификатором размера для указателя) будет допустимым.
Что касается замены «старших и младших битов регистра», J-16 SDiZ предлагает ror bx, 8
для замены 9.0041 bl и bh
(и IIRC, это оптимальный способ сделать это). Однако, если вы хотите обменять бит 0 (скажем) bl
на бит 7 bl
, вам понадобится больше логики.
DI — это не указатель, это индекс.
Вы можете ROR BX, 8
чередовать младший/старший байт регистра.
Зарегистрируйтесь или войдите в систему
Зарегистрируйтесь с помощью Google Зарегистрироваться через Facebook Зарегистрируйтесь, используя адрес электронной почты и парольОпубликовать как гость
Электронная почтаТребуется, но не отображается
Опубликовать как гость
Электронная почтаТребуется, но не отображается
Нажимая «Опубликовать свой ответ», вы соглашаетесь с нашими условиями обслуживания и подтверждаете, что прочитали и поняли нашу политику конфиденциальности и кодекс поведения.
Можно ли вычесть два указателя на ассемблере?
спросил
Изменено 4 года, 3 месяца назад
Просмотрено 2к раз
Я столкнулся со следующим фрагментом кода и пытаюсь его концептуально понять:
mov si,offset v5 мов ди, смещение v2 суб си, ди
v5
и v2
относятся к следующим данным:
v2 dw 4 v5 дв 3
Насколько я понимаю, это касается концепции косвенной адресации в языке ассемблера x86. Я знаю, что регистры si и di не равны значениям, а просто указывают местоположение. Итак, каким будет ответ от вычитания двух указателей, как в приведенном выше коде? Возможно ли это?
- указатели
- сборка
- x86
- intel
- адресация
Да, указатели — это просто целые числа, конечно, вы можете их вычесть, например. с
sub si, di
.
Предполагая, что они являются смещениями относительно одной и той же базы сегментов (например, крошечная/маленькая или плоская модель памяти), результат на самом деле имеет смысл: расстояние в байтах между указанными ячейками памяти.
Одним из вариантов использования является то, что упоминал @fuz: получение индекса массива из указателя. например вы можете реализовать strlen
, увеличив указатель, а затем в конце сделать sub ax, si
, чтобы вернуть длину.
Конечно, для меток, определенных в текущем файле, расстояние является константой времени сборки, поэтому вы должны просто попросить ассемблер вычислить его для вас. Я думаю, что mov si, OFFSET v5 - v2
— правильный синтаксис MASM. В NASM было бы всего мов си, v5 - v2
. И с этими определениями вы получите si=2
независимо от того, делаете ли вы это во время сборки с v5 - v2
или с инструкцией sub
во время выполнения, потому что dw 4
имеет ширину 2 байта.