Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Структуры данных - лекция: строки в Си, прямой ...

Anton
January 11, 2025

Структуры данных - лекция: строки в Си, прямой и обратный порядок байт, представление чисел с плавающей точкой

Лекция курса "Структуры данных"
Некоторые типы данных в Си/С++: работа со строками, прямой и обратный порядок байт, числа с плавающей точкой (стандарт IEEE-754)

- Строки в Си и С++
- Строки в стиле Си
- const char* vs char[]
- Прямой и обратный порядок байт
- Двоичное представление чисел с плавающей точкой: стандарт IEEE-754

https://vk.com/video53223390_456239479

Anton

January 11, 2025
Tweet

More Decks by Anton

Other Decks in Education

Transcript

  1. Некоторые типы данных в С++: работа со строками, прямой и

    обратный порядок байт, числа плавающей точкой (стандарт IEEE-754),
  2. Строки в Си и С++ • Стиль Си (C-style strings):

    массив байт char - набор функций: strlen, strcpy, strcmp, sprintf - полезно уметь работать для разработки встраиваемых систем • Стиль С++ (C++-style strings): класс std::string - строка как специальный тип данных - операторы и функции внутри класса - дополнительный контроль памяти для некоторых операций - красивее с точки зрения ООП
  3. Строки в стиле Си • Строка — массив байт •

    Можно объявить как массив • Можно — как динамический массив (указатель на массив байт) • Завершающий 0 • Библиотечный вызовы: strlen, strcpy, strcmp, sprintf • char[] vs const char*
  4. Примеры с обрезанием 0-м • Создать строку, напечатать, добавить 0

    по индексу, еще раз напечатать • Убрать ноль, напечатать без нуля (должен вылезти мусор) • Попробовать объявить две строки последовательно и срезать ноль с первой — вылезет ли вторая • Разместить в одном буфере несколько строк, разделенных нулями • Отметить отдельно, что нужно оставить один байт в конце под этот ноль
  5. Давайте разберемся со строками • Сначала создать обычную строку char[]=»»

    • Сделать strlen • Сделать sizeof (на 1 байт больше, чем strlen) • Сделать strcpy • Поиграть с завершающим нулем: - вставить несколько нулей вручную - перенастроить указатель на середину строки - попробовать удалить завершающий ноль - и т. п.
  6. Давайте разберемся со строками • Создать строку const char •

    На вид все то же самое: можно сделать strlen (sizeof уже не пойдет, ну и что), strcpy • Записать в строку не получится (показать, что при попытке вставить ноль по указателю ругается компилятор, но можно попробовать передать в качестве источника в strcpy — скорее всего тоже не получится) • Но мы шиты не лыком: настроим обычный указатель на эту же строку — получим сегфолт • Показать адрес строки const char и адрес строки char []: одна находится в памяти ридонли, вторая — в памяти только для чтения
  7. Отладчики в Linux • gdb (GNU Debugger) • ddd (Data

    Display Debugger) — графический интерфейс к gdb • Nemiver, Kdbg, … Внутри среды разработки • KDevelop • QtCreator • Ghidra ghidra-sre.org (NSA, открывается только через VPN) github.com/NationalSecurityAgency/ghidra
  8. Собрать для отладки (gdb и интерфейсы) • Собрать исполняемый файл

    с информацией для отладки (debug info): g++ -g str-test.cpp -o str_tests • Исполняемый файл str_tests загрузить в отладчик через меню выбора файла • Появится исходный код и интерфейс для точек останова, запуска, просмотра значений и т.п.
  9. Неудобства • Нашел, как посмотреть адрес переменной только в QtCreator

    • Память можно смотреть только отдельными участками, указав стартовый адрес • Просмотр по сегментам не нашел ни в одном из отладчиков
  10. Сегменты памяти для запущенного приложения • Запустить приложение в режиме

    отладки или зациклить или поставить на ввод (чтобы не завершилось) • Узнать pid (идентификатор процесса) ps -A | grep str-test 12338 ? 00:00:00 str-test • Вывести сегменты памяти для приложения cat /proc/12338/maps
  11. 00400000-00401000 r-xp 00000000 103:05 4337926 /home/user/cpp_tests/str-test 00600000-00601000 r--p 00000000 103:05

    4337926 /home/user/cpp_tests/str-test 00601000-00602000 rw-p 00001000 103:05 4337926 /home/user/cpp_tests/str-test 00602000-00634000 rw-p 00000000 00:00 0 [heap] 7ffff716c000-7ffff7182000 r-xp 00000000 103:02 2102380 /lib/x86_64-linux-gnu/libgcc_s.so.1 7ffff7182000-7ffff7381000 ---p 00016000 103:02 2102380 /lib/x86_64-linux-gnu/libgcc_s.so.1 7ffff7381000-7ffff7382000 rw-p 00015000 103:02 2102380 /lib/x86_64-linux-gnu/libgcc_s.so.1 7ffff7382000-7ffff748a000 r-xp 00000000 103:02 2097345 /lib/x86_64-linux-gnu/libm-2.23.so 7ffff748a000-7ffff7689000 ---p 00108000 103:02 2097345 /lib/x86_64-linux-gnu/libm-2.23.so 7ffff7689000-7ffff768a000 r--p 00107000 103:02 2097345 /lib/x86_64-linux-gnu/libm-2.23.so 7ffff768a000-7ffff768b000 rw-p 00108000 103:02 2097345 /lib/x86_64-linux-gnu/libm-2.23.so 7ffff768b000-7ffff784b000 r-xp 00000000 103:02 2097353 /lib/x86_64-linux-gnu/libc-2.23.so 7ffff784b000-7ffff7a4b000 ---p 001c0000 103:02 2097353 /lib/x86_64-linux-gnu/libc-2.23.so 7ffff7a4b000-7ffff7a4f000 r--p 001c0000 103:02 2097353 /lib/x86_64-linux-gnu/libc-2.23.so 7ffff7a4f000-7ffff7a51000 rw-p 001c4000 103:02 2097353 /lib/x86_64-linux-gnu/libc-2.23.so 7ffff7a51000-7ffff7a55000 rw-p 00000000 00:00 0 7ffff7a55000-7ffff7bc7000 r-xp 00000000 103:02 2628418 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21 7ffff7bc7000-7ffff7dc7000 ---p 00172000 103:02 2628418 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21 7ffff7dc7000-7ffff7dd1000 r--p 00172000 103:02 2628418 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21 7ffff7dd1000-7ffff7dd3000 rw-p 0017c000 103:02 2628418 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21 7ffff7dd3000-7ffff7dd7000 rw-p 00000000 00:00 0 7ffff7dd7000-7ffff7dfd000 r-xp 00000000 103:02 2097349 /lib/x86_64-linux-gnu/ld-2.23.so 7ffff7fb5000-7ffff7fbb000 rw-p 00000000 00:00 0 7ffff7ff8000-7ffff7ffb000 r--p 00000000 00:00 0 [vvar] 7ffff7ffb000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso] 7ffff7ffc000-7ffff7ffd000 r--p 00025000 103:02 2097349 /lib/x86_64-linux-gnu/ld-2.23.so 7ffff7ffd000-7ffff7ffe000 rw-p 00026000 103:02 2097349 /lib/x86_64-linux-gnu/ld-2.23.so 7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0 [stack] ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]
  12. Understanding Linux /proc/id/maps stackoverflow.com/questions/1401359/understanding-linux-proc-id-maps#1401595 • address - This is the

    starting and ending address of the region in the process's address space • permissions - This describes how pages in the region can be accessed. There are four different permissions: read, write, execute, and shared. If read/write/execute are disabled, a - will appear instead of the r/w/x. If a region is not shared, it is private, so a p will appear instead of an s. If the process attempts to access memory in a way that is not permitted, a segmentation fault is generated. Permissions can be changed using the mprotect system call. • offset - If the region was mapped from a file (using mmap), this is the offset in the file where the mapping begins. If the memory was not mapped from a file, it's just 0. • device - If the region was mapped from a file, this is the major and minor device number (in hex) where the file lives. • inode - If the region was mapped from a file, this is the file number. • pathname - If the region was mapped from a file, this is the name of the file. This field is blank for anonymous mapped regions. There are also special regions with names like [heap], [stack], or [vdso]. [vdso] stands for virtual dynamic shared object. It's used by system calls to switch to kernel mode.
  13. const char* vs char[] • char[] - расположен на стеке

    (память чтение/запись) • const char* - память только для чтения • Компилятор ругается, но можно его обойти • И поймать segfault • Но не с const char[] (он тоже пойдет на стек)
  14. Прямой и обратный порядок байт • Big endian (тупоконечники) vs

    little endian (остроконечники) • Числовые значения, занимающие более 1 байта на разных архитектурах могут быть представлены разным образом • Например: int или float 4 байт • Прямой порядок: младший байт идёт раньше старшего слева направо (в этом есть логика) • Обратный порядок: при записи чисел у нас старшие биты слева, а младшие справа, с обратным порядком байт данные будут выстроены так, что двоичная запись будет сразу представлять корректное значение • Прямой порядок: Intel x86
  15. стандарт IEEE-754 ru.wikipedia.org/wiki/IEEE_754-2008 ieeexplore.ieee.org/document/4610935 • принят в 1985 году •

    www.h-schmidt.net/FloatConverter/IEEE754.html • www.binaryhexconverter.com/hex-to-binary-converter • www.binaryhexconverter.com/binary-to-decimal-converter
  16. 32 бит float • Знак (1 бит) • Экспонента (степень

    двойки) (8 бит) • Мантисса (старшая единица опущена) (23 бит)
  17. • Си/С++ - тонкий слой абстракции над архитектурой компьютера. •

    Чтобы хорошо понимать, что происходит внутри программы на С++ лучше читать книгу про структуру памяти и архитектуру компьютера, а не про синтаксис С++. • Рекомендую Харрис и Харрис. • Ява или Пайтон — толстый слой абстракции, там процессор спрятан поглубже за виртуальной машиной (хотя такую книгу лучше прочитать все равно). • Также архитектура компьютера - слой абстракции над микроархитектурой (внутреннее устройство) компьютерного чипа, который - абстракция над физическим воплощением чипа в железе (в процессе проектирования и производства чипов может встретиться еще несколько слоев абстракций).