C – это язык программирования общего назначения. Он использовался для написания систем UNIX и используется для разработки большинства программ, которые на них работают. Его называют «языком системного программирования», потому что он полезен для написания операционных систем. Некоторые компиляторы, которые представляют собой компьютерные программы, переводящие компьютерный код с одного языка программирования (исходный язык)на другой (целевой язык), были написаны на C.

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

С другой стороны, аппаратные элементы взаимодействуют друг с другом на языке, понятном этим системам. Этот тип языка называется языком программирования низкого уровня и подразделяется на машинный язык и язык ассемблера. На машинном языке инструкции записываются в двоичной системе счисления, а на языке ассемблера инструкции записываются набором букв и символов.

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

Для C доступно несколько компиляторов, таких как Turbo C/C++, Borland C/++ и т. д., но наиболее популярным является GCC.

Что такое GCC?

GCC расшифровывается как Коллекция компиляторов GNU. Это интегрированный дистрибутив компиляторов, написанный на языке C и разработанный GNU Project, который поддерживает множество языков программирования: C, C++, Objective-C, Fortran, Go и другие.

Обычно имя компилятора связывают с каждым поддерживаемым языком программирования, например: G++ для C++, GNAT для Ada и GCC для C, что понимается как «компилятор GNU C». Все эти компиляторы нацелены на то, чтобы генерировать машинный код непосредственно для чтения и выполнения процессором (например, логическим чипом).

Процесс компиляции, выполняемый компилятором GCC, состоит из четырех этапов: предварительная обработка, компиляция, ассемблирование и связывание.

В Linux есть команда под названием gcc, которая создает исполняемый файл из файла .c при ее вводе. Синтаксис команды следующий:

[me@linuxbox:~]$ gcc -[options] [filename]

Отсюда и до конца блога, в качестве примера, предположим, что на компьютере есть файл C с именем main.c. Инструкции, написанные внутри main. c следующее:

#include <stdio.h>

/**
 * main - Prints a message
 *
 * Return: 0 
 */
int main(void)
{
   prtinf("Hello World\n");
   return (0);
}

В его состав входят: библиотека ‹stdio.h›, позволяющая производить ввод и операции, а также определения, необходимые для этих операций; комментарий к разделу, описывающий использование кода; основная функция, в которой находятся инструкции.

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

[me@linuxbox:~]$ gcc main.c
[me@linuxbox:~]$ ls
main.c  a.out
[me@linuxbox:~]$

Результатом будет файл с именем a.out, который запускается компьютером. Если исполняемый файл должен иметь имя, отличное от сгенерированного по умолчанию, есть опция, позволяющая установить его, то есть ввести -o, за которым следует целевое имя (например, cisfun):

[me@linuxbox:~]$ gcc main.c -o execmain
[me@linuxbox:~]$ ls
main.c  cisfun
[me@linuxbox:~]$

Чтобы выполнить выходной файл, необходимо ввести ./‹filename› в Shell. Взяв файл a.out, введите команду:

[me@linuxbox:~]$ ./a.out
Hello World
[me@linuxbox:~]$

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

1. Предварительная обработка

C предоставляет определенные средства языка с помощью препроцессора, который является первым шагом в компиляции. Наиболее часто используемые из них: #include,для включения содержимого файла во время компиляции и #define. , чтобы заменить токен произвольной последовательностью символов. Кроме того, препроцессор удаляет комментарии исходного файла.

1.1 Включение файла

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

#include "filename"
#include <filename>

Имя файла, указанное в кавычках, ищется при обнаружении исходной программы. Но, если он не найден там или если имя заключено в ‹ и ›, поиск выполняется по правилу, определенному реализацией, чтобы найти файл. Существуют часто используемые строки #include, такие как объявления заголовков (например, ‹stdio.h›) и библиотечные функции.

1.2 Замена макросов

Синтаксис определения выглядит следующим образом:

#define name replacement-text

Подстановка макроса заменит все вхождения, где записано имя маркера, текстом replacement-text. Замены производятся только для токенов. Это означает, что не заменены цитируемые вхождения.

Чтобы сгенерировать файл предварительной обработки, необходимо ввести команду gcc с параметром -E, как показано далее:

[me@linuxbox:~]$ gcc -E main.c > preprocessor
[me@linuxbox:~]$ ls
main.c  preprocessor
[me@linuxbox:~]$

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

[me@linuxbox:~]$ cat preprocessor
code of stdio.h file
int main(void)
{
   prtinf("Hello World\n");
   return (0);
}
[me@linuxbox:~]$

2. Компиляция

Компиляция берет выходной файл препроцессора и генерирует код сборки. В Linux командная строка, позволяющая создать этот файл, называется gcc с параметром -S:

[me@linuxbox:~]$ gcc -S main.c
[me@linuxbox:~]$ ls
main.c  main.s  preprocessor
[me@linuxbox:~]$

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

[me@linuxbox:~]$ cat main.s
    .file   "main.c"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $0, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609"
    .section    .note.GNU-stack,"",@progbits
[me@linuxbox:~]$

3. Соберите

Этот компонент GCC берет ассемблерный код и преобразует его в машинный код. Это означает, что это объектный файл с языком низкого уровня. Командная строка, которая генерирует этот тип кода, называется gcc с параметром -S:

[me@linuxbox:~]$ gcc -c main.c
[me@linuxbox:~]$ ls
main.c  main.o  main.s  preprocessor
[me@linuxbox:~]$

На этом шаге выходной файл имеет расширение .o. Если этот файл открыт, то можно увидеть символы, непонятые машиной:

[me@linuxbox:~]$ cat -v main.o | head
^ELF^B^A^A^@^@^@^@^@^@^@^@^@^A^@>^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^P^B^@^@^@^@^@^@^@^@^@^@@^@^@^@^@^@@^@^K^@^H^@UHM-^IM-eM-8^@^@^@^@]M-C^@GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609^@^T^@^@^@^@^@^@^@^AzR^@^Ax^P^A^[^L^G^HM-^P^A^@^@^\^@^@^@^\^@^@^@^@^@^@^@^K^@^@^@^@A^N^PM-^F^BC^M^FF^L^G^H^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^D^@M-qM-^?^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^B^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^C^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^E^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^F^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@^D^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^H^@^@^@^R^@^A^@^@^@^@^@^@^@^@^@^K^@^@^@^@^@^@^@^@main.c^@main^@^@^@^@ ^@^@^@^@^@^@^@^B^@^@^@^B^@^@^@^@^@^@^@^@^@^@^@^@.symtab^@.strtab^@.shstrtab^@.text^@.data^@.bss^@.comment^@.note.GNU-stack^@.rela.eh_frame^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^[^@^@^@^A^@^@^@^F^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@@^@^@^@^@^@^@^@^K^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@!^@^@^@^A^@^@^@^C^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@K^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@'^@^@^@^H^@^@^@^C^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@K^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@,^@^@^@^A^@^@^@0^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@K^@^@^@^@^@^@^@5^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@5^@^@^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@M-^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@J^@^@^@^A^@^@^@^B^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@M-^@^@^@^@^@^@^@^@8^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^H^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@E^@^@^@^D^@^@^@@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@M- ^A^@^@^@^@^@^@^X^@^@^@^@^@^@^@    ^@^@^@^F^@^@^@^H^@^@^@^@^@^@^@^X^@^@^@^@^@^@^@^Q^@^@^@^C^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@M-8^A^@^@^@^@^@^@T^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^B^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@M-8^@^@^@^@^@^@^@M-X^@^@^@^@^@^@^@
^@^@^@^H^@^@^@^H^@^@^@^@^@^@^@^X^@^@^@^@^@^@^@  ^@^@^@^C^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@M-^P^A^@^@^@^@^@^@^M^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^A^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@[me@linuxbox:~]$

4. Связывание

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

На этом шаге уже создан исполняемый файл (main).

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

[me@linuxbox:~]$ gcc –Wall –save-temps main.c –o main
[me@linuxbox:~]$ ls
main.c  main.o  main.s  main  preprocessor
[me@linuxbox:~]$

Если «основной» файл выполняется, результатом будет напечатанное сообщение:

[me@linuxbox:~]$ ./main
Hello World
[me@linuxbox:~]$

ССЫЛКИ

  • КЕРНИГАН, Б. РИЧ, Д. (1988). Язык программирования Си. Нью-Джерси: Прентис Холл.
  • БЬЮКЕНЕН, Вт (1997). Разработка программного обеспечения для инженеров. Эльзевир. ISBN: 978–0–340–70014–3.