Cat

Сравнение типизации Python и C

Этот пост открывает новую рубрику – "Сравнение Python и C". В этом посте я сравню типизации высокоуровнего языка Python и низкоуровневого языка C. Покажу, как скомпилировать и запустить программу на языке С.

Дополнительные материалы

Icon Link

Реклама

Icon Link
Сравнение Python и С/C++ Arduinum628 24 Декабрь 2023 Просмотров: 873

Всем доброго дня! На канале начинается новая рубрика - "Сравнение языка Python 3 и C". Чем отличается высокоуровневый Python от низкоуровневого C? Что такое компилятор? Как работает интерпретатор Python? Как подружить Python и C? Как пк взаимодействует с низкоуровневыми языками? На эти и другие вопросы, связанные с данной темой, ответит новая рубрика. Все примеры я буду писать и запускать в операционной системе Kubuntu. Kubuntu - производный от Ubuntu дистрибутив Linux. Приготовьтесь к открытиям и экспериментам. Погружение в низкий уровень начинается...

Сравнение типизации

Нам известно, что Python имеет динамическую типизацию. Это означает, что типы переменных определяются во время выполнения программы и могут измениться на лету во время выполнения программы. Это даёт некоторую гибкость использования данных в Python.

age = 20
print('Возраст пользователя ' + str(age) + 'лет')

В примере выше мы преобразуем данные переменной age в строку, складываем строку и выводим результат. Как же обстоят дела с типизацией в С? В языке С типизация является статической. Это значит, что типы переменных будут определяться на этапе компиляции. Что же такое, собственно, компиляция? Компиляция - это процесс преобразования исходного кода программы в машинный код или байт-код. Этот процесс выполняет программа-компилятор. В этой статье я покажу вам, как запускать С код. Однако более подробно про компиляцию и компилятор мы поговорим в следующих статьях, а пока давайте вернёмся к типизации языка С. К сожалению, в С нет возможности преобразования типа на лету, но есть удобный способ форматирования данных для вывода в консоль.

int age = 20;
printf('Возраст пользователя %d лет', age);

В данном примере мы строго указываем тип при создании переменной, а также указываем спецификатор формата %d (целое число int типа), который укажет, какой тип данных ожидать при выводе. Функция printf выведет данные в консоль. Я думаю, читатель заметит схожесть вставки данных из переменных с оператором % из Python для форматирования строк. Давайте посмотрим как это выглядит в Python.

age: int = 20
print('Возраст пользователя %d лет' % age)

Главным отличием будет то, что в Python при форматировании строки % произойдёт преобразование типа int в str на лету, в то время как в примере с языком С форматирование происходит для вывода в консоль и при этом тип данных при выводе не меняется. Также, начиная с Python 3.6 и выше, можно указать типы переменных в синтаксисе, если это необходимо для улучшения читаемости кода (как в примере выше). В версии Python 3.5 это делалось в комментарии age = 20 # type: int. Это называется "аннотация типов". После этого вы сможете изменить тип переменной, но некоторые IDE будут подсвечивать вам подсказки при неправильной работе с типом данных. Например, PyCharm поддерживает аннотации. На работу программы это влиять не будет, типизация в Python по-прежнему будет динамической. Однако это будет работать на уровне соглашения между разработчиками. Если в переменной указан тип int, значит, разработчики не будут менять тип данных для переменной.

Оба вида типизации обладают своими преимуществами и недостатками. Преимущество динамической типизации в Python над статической в С том, что она позволяет писать код быстрее и делает его более гибким. Почему так?Преобразование типов данных происходит на лету, а сам синтаксис получается короче. Соответственно, C не такой гибкий и быстрый в написании кода. Преимущество статической типизации С над динамической Python в том, что при компиляции программы мы видим все ошибки в коде сразу. Также статическая типизация выигрывает у динамической типизации в скорости выполнения программы из-за того, что при динамической типизации приходится тратить дополнительное время для проверки типов во время выполнения программы.

Собственно говоря, я упоминал о выводе данных в консоль, но как вывести результат нашей программы, написанной на С? Достаточно ли этих двух строк для работы программы?

Для тестирования нашей программы нам необходим компилятор. Я буду использовать компилятор gcc, который уже был предустановлен в моей операционной системе Kubuntu. Посмотрим версию нашего компилятора, чтобы убедиться что он присутствует в операционной системе.

В terminal

$ gcc --version
gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0  
Copyright (C) 2021 Free Software Foundation, Inc.  
This is free software; see the source for copying conditions.  There is NO  
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Вывод выше показывает, что у нас установлена версия компилятора 11.4.0. Это означает, что мы можем приступить к сборке программы и увидеть результат? Ответ "да", но только если мы добавим дополнительные строки в нашу программу.

#include <stdio.h>
int main(){
    int age = 20;
    printf('Возраст пользователя %d лет', age);
    return 0;
}

Итак, что мы добавили за строки? Строка #include <stdio.h> подключает стандартную библиотеку для С, в которой содержится функционал для ввода/вывода в том числе функция printf, которую мы используем в нашем коде. Функция main является обязательной и в случае успеха возвращает 0 по умолчанию (С99 и новее). Также можно прописывать return 0, что не будет ошибкой, особенно для более старых версий. Я решил оставить вариант с return 0, так как он более универсален. Наш файл с кодом мы должны сохранить в файл расширением .c. Пусть это будет age_print.c.

Давайте с вами скомпилируем программу для получения исполняемого файла. Для этого нам нужно, находясь в terminal, перейти в папку с нашим файлом age_print.c и дать команду компиляции.

В terminal

$ gcc age_print.c -o age_print
age_print.c: In function ‘main’:
age_print.c:5:12: warning: character constant too long for its type
    5 |     printf('Возраст пользователя %d лет', age);
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
age_print.c:5:12: warning: passing argument 1 of ‘printf’ makes pointer from integer without a cast [-Wint-conversion]
    5 |     printf('Возраст пользователя %d лет', age);
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |            |
      |            int
In file included from age_print.c:1:
/usr/include/stdio.h:356:43: note: expected ‘const char * restrict’ but argument is of type ‘int’
  356 | extern int printf (const char *__restrict __format, ...);

Рассмотрим команду подробнее. Мы говорим gcc компилятору скомпилировать исходный код с именем age_print.c и создать исполняемый файл age_print. На название файла указывает флаг -o. Под командой в terminal мы видим вывод. Что же это за вывод такой? Это предупреждения отладчика. В нашем случае я специально указал не те кавычки, чтобы показать вам, что произойдёт, когда показываются предупреждения при компиляции. Более подробно о компиляции вы узнаете в следующих статьях. При замене на "" кавычки эти предупреждения пропадут. Исправим наш код и добавим перенос \n строки для более красивого вывода результата работы программы.

#include <stdio.h>
int main(){
    int age = 20;
    printf("Возраст пользователя %d лет\n", age);
    return 0;
}

Повторно запустим команду выше и посмотрим на результат. При успешной компиляции мы не видим никакого сообщения в terminal. Но мы видим, что рядом с нашим age_print.c появился исполняемый файл age_print. Файл появился в результате успешной компиляции без ошибок.

В terminal

$ ./age_print
Возраст пользователя 20 лет

Поздравляю, мы написали нашу первую программу на C, скомпилировали и запустили её. Моя рубрика сравнивает Python и C, и, раз я затронул в этой статье тему компиляции, в следующей статье я раскрою тему выполнения программ на обоих языках. Вы узнаете, чем компилятор С отличается от интерпретатора Python. Дальше будет ещё интереснее :)

Заключение

  1. При объявлении переменной в С мы явно указываем тип в отличие от Python, но зато в Python есть аннотация для типов данных;
  2. В отличие от Python язык С не способен преобразовывать типы данных на лету для вставки данных, но есть удобный способ форматирования данных для вывода в консоль;
  3. Язык с динамической типизацией быстрее в разработке и код более гибкий;
  4. Язык со статической типизацией быстрее выполняется и все ошибки кода видны сразу при компиляции;
  5. Посмотрели как скомпилировать код и запустить программу на С.

Автор

    Нет комментариев

    Реклама

Поделиться