Вывести содержимое памяти c

Вывести содержимое (в шестнадцатеричном виде) 16 байтов по указанному адресу

Я пытаюсь отобразить содержимое определенного адреса, используя символ * для этого адреса. До сих пор я пытался сделать это, используя следующую реализацию

Но я продолжаю получать сообщение об ошибке «Ошибка сегментации (основной дамп)». Я попытался создать фиктивный указатель для проверки

Но ошибка все еще сохраняется

Решение

Мне трудно объяснить, в чем проблема, потому что почти каждая строка в вашем коде неверна.

Вот что я бы сделал:

Другие решения

Вам нужно перебирать содержимое адреса и печатать каждый из них по отдельности, пока не дойдет до 16. Пример кода:

Адрес 0x7ffe5b86a777: 0677A7865BFE7F000060054000000000

Если у вас уже есть указатель на адрес, с которого вы хотите распечатать содержимое, вы можете передать его прямо на printf , как это:

Если arguments не указатель на память, из которой вы хотите распечатать содержимое, тогда я не понимаю, что это на самом деле является и мне нужно, чтобы ты объяснил лучше.

Примечания к приведенному выше образцу кода:

  1. Использовать %p без провоцирования неопределенного поведения, вы должны явно привести указатель к [const] void * если это уже не [const] void * , Так как printf принимает переменное число аргументов, компилятор не знает ожидаемых типов своих аргументов, поэтому он не вставляет это преобразование для вас, как это было бы с обычной функцией, которая принимает [const] void * аргумент.
  2. Двойной актерский состав (unsigned int)(unsigned char) заставляет char читать из arguments[i] быть расширенным до нуля, а не расширенным до ширины unsigned int , Если вы этого не сделаете, значения от 0x80 и выше могут быть напечатаны с набором ведущих F (например, ffffff80 ) что, вероятно, не то, что вы хотите.

Это будет по-прежнему зависать, если по указанному адресу не будет 16 байт читаемой памяти. В вашем примере

там только гарантированно будет один байт читаемой памяти по адресу foo , (Вероятно, он будет работать на любом компьютере, к которому вы можете легко добраться, но все равно допускается сбой в соответствии с буквой стандарта C.)

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

Во-вторых, если вы не знаете arguments указатель выровнен соответствующим образом, загружая int через этот указатель может произойти сбой из-за невыровненного доступа. (Что вполне может проявиться как нарушение сегментации.) Вероятно, вы не можете принять правильное выравнивание для этой процедуры.

В-третьих, если вам нужно распечатать 16 байтов, то int будет (как правило) только 4 или 8 из них. Будет сложнее использовать стандартные процедуры печати для объединения всех частей, чем писать побайтный цикл. (См. Ответ выше для примера такого цикла.)

Я думаю, что вы либо слишком усложняете это, либо недостаточно описали фактический вклад. Это указатель на указатель?

В любом случае, чтобы сделать это простым способом с некоторым указателем на память, вы можете сделать это, например, следующим образом (C-like C ++, извините, сделано в спешке онлайн в web cpp.sh):

Чтобы напечатать 16 байтов, просто измените аргумент размера.

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

Довольно давно я использую следующую функцию для печати содержимого области памяти:

Для программ на C удалите noexcept ключевое слово.

Источник

Исследование памяти с помощью GDB

Адрес и размер: & и sizeof()

Переменные в С — это непрерывные блоки памяти. Каждый такой блок характеризуется двумя числами:

  1. адресом первого байта в блоке;
  2. размером блока в байтах.

Язык С позволяет узнать адрес переменной в памяти с помощью оператора & , а функция sizeof() вычисляет размер блока памяти занимаемого переменной.

С помощью GDB вы можете проделать следующее:

Это значит, что переменная i размещается по адресу 0xbffff1b8 и занимает в памяти 4 байта.

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

То есть, по крайней мере, на моей машине, переменные типа int занимают четыре байта, а типа double — восемь байт.

Содержимое памяти по адресу: x

Для более детального анализа содержимого памяти в GDB есть команда x , которая проверяет (eXamine, отчего и происходит ее название) память, начиная с определенного адреса. Формат команды определяет, сколько байт вы хотите проверить и в каком виде вывести их на экран:

  • n : количество выводимых элементов
  • f : формат вывода (десятичный, шестнадцатиричный. )
  • u : размер единицы данных (байт ( b ), слово ( w ), . )

Рассмотрим с помощью x «внутренности» простейшей программы

Запустим ее в отладчике и остановимся на первой строке кода.

Мы вывели на экран 4 байта, начиная с адреса &i , поскольку именно столько места занимает в памяти переменная i . Заметим, что она еще не инициализирована.

Сделав еще один шаг, получим

Обратите внимание, что на машинах Intel байты хранятся в порядке «от младшего к старшему», то есть справа налево, в отличии от более привычной нам записи слева направо.

Переменная j расположена в памяти через 4 байта от ранее объявленной i и содержит «мусор». В то же время c1 , хотя и объявлена в тексте программы позже i , но в памяти расположена раньше, занимая 1 байт, как и положено символу. Это интересно, поскольку можно было предположить другое поведение компилятора. Дело в том, что работа с отдельными байтами медленнее и «дороже» работы с целыми словами (то есть с 4-мя байтами для 32-разрядных машин и 8-ю байтами — для 64-разрядных). Поэтому, в целях повышения быстродействия, компилятор мог бы позволить дополнительный расход памяти и выделить под символ целое слово. Однако этого не произошло.

Более экзотический пример — выведем 4 слова (w), начиная с адреса функции main :

Команда ptype показывает тип C-выражения. Именно выражения, а не переменной:

Теперь с помощью GDB можно проиллюстрировать особенность реализации массивов в С, а именно, что имя массива является указателем на его первый элемент.

Добавим в нашу программу массив:

Переменная a имеет следующий тип:

Теперь посмотрим как выглядит область памяти, занятая массивом:

Тот же результат мы получим, если используем имя массива в качестве указателя на его (массива) первый элемент:

Мы можем применять к a арифметические операции:

Это означает, что a + 1 — это указатель на int, который содержит адрес 0xbffff1с4. Что же находится по этому адресу?

А находится там элемент a[1] массива a . Другой способ убедиться в этом — это разыменовать указатель a + 1

Итак, в С a[i] эквивалентно *(a + i) . Проверяем:

Просмотр локальных переменных: info locals

Вывести список локальных автоматических переменных можно командой info locals :

Как видно, на момент просмотра массив a еще не инициализирован.

Читайте также

Комментарии

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

Источник

Вывести двоичное содержимое k битов памяти с адреса adr

1. Разработайте функцию, которая выдаст на экран двоичное содержимое k битов памяти с адреса adr.
2. Разработайте функцию для определения количества единиц в двоичном содержимом k битов оперативной памяти, начиная с адреса adr.
Только решение попроще, чтобы я понял, что вы сделали Хочу понять!

Комментарий модератора
П.5.16.Правил
Запрещено создавать темы с множеством вопросов во всех разделах, кроме разделов платных услуг. Один вопрос — одна тема.

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Функция должна вывести cnt битов, расположенных в памяти, начиная с адреса addr
дана функция: void dump(void* addr, int cnt); Функция должна вывести cnt битов, расположенных в.

Содержимое ячейки памяти = CA16. Какое там записано двоичное, восьмеричное, десятичное число
Нужно написать программу для 16 разрядного ассемблера: Содержимое ячейки памяти = CA16. Какое там.

Выделить в памяти 1024 ячейки по 8 байт и вывести их адреса(МИНИ менеджер памяти))
Вот тут появилась такая интересная задача: требуется сделать программу которая управляет 1024.

В поле дампа памяти вывести на экран содержимое данной памяти [bx+di]
Имеется функция IDIV word ptr . Но предварительно мы записываем значение в данную область памяти.

Из битов в двоичное представление числа
У меня есть класс для работы с битовыми массивами. Не получается сделать метод для перевода из.

Вывести содержимое только тех тегов, где указаны адреса почты
Здравствуйте! Проблема с регулярным выражением. Есть файл на php, в нем есть адреса почты (они.

Докажите, что двоичное представление числа n>=1 содержит [lg2n]+1 битов
Докажите, что двоичное представление числа n>=1 содержит +1 битов

Вывести значения элементов массива и их адреса в памяти
Поставьте комментарии рядом с каждой строчкой 🙂 Задача:составить программу в которой случайным.

Как вывести содержимое ячеек памяти BIOS
Я чайник в ассемблерных вставках Работаю через DosBox -> в Turbo Pascal Нужно вывести содержимое.

Источник

Управление памятью в C++

Работа с динамической памятью зачастую является узким местом во многих алгоритмах, если не применять специальные ухищрения.

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

0. А нужна ли нам ручная работа с памятью?

В первую очередь проверим, насколько умный аллокатор может ускорить работу с памятью.

Напишем простые тесты для C++ и C# (C# известен прекрасным менеджером памяти, который делит объекты по поколениям, использует разные пулы для объектов разных размеров и т.п.).

Несмотря на всю «сферично-вакуумность» примера, разница по времени получилась в 10 раз (62 ms против 650 ms). Кроме того, c#-пример закончен, а по правилам хорошего тона в c++ выделенные объекты надо удалить, что ещё больше увеличит отрыв (до 2580 ms).

1. Пул объектов

Очевидное решение — забрать у ОС большой блок памяти и разбить его на равные блоки размера sizeof(Node), при выделении памяти брать блок из пула, при освобождении — возвращать в пул. Пул проще всего организовать с помощью односвязного списка (стека).

Поскольку стоит задача минимального вмешательства в программу, всё что можно будет сделать, это добавить примесь BlockAlloc к классу Node:

Прежде всего нам понадобится пул больших блоков (страниц), которые забираем у ОС или C-runtime. Его можно организовать поверх функций malloc и free, но для большей эффективности (чтобы пропустить лишний уровень абстракции), используем VirtualAlloc/VirtualFree. Эти функции выделяют память блоками, кратными 4K, а также резервируют адресное пространство процесса блоками, кратными 64K. Одновременно указывая опции commit и reserve, мы перескакиваем ещё один уровень абстракции, резервируя адресное пространство и выделяя страницы памяти одним вызовом.

Затем организуем пул блоков заданного размера

Комментарием // todo: lock(this) помечены места, которые требуют межпоточной синхронизации (например, используйте EnterCriticalSection или boost::mutex).

Объясню, почему при «форматировании» страницы не ипользуется абстракция FreeBlock для добавления блока в пул. Если бы было написано что-то вроде

То страница по принципу FIFO оказалась бы размеченной «наоборот»:

Несколько блоков, затребованных из пула подряд, имели бы убывающие адреса. А процессор не любит ходить назад, от этого у него ломается Prefetch (UPD: Не актуально для современных процессоров). Если же делать разметку в цикле

то цикл разметки ходил бы по адресам назад.

Теперь, когда приготовления сделаны, можно описать класс-примесь.

Объясню, зачем нужны проверки if (s != sizeof(T))
Когда они срабатывают? Тогда, когда создаётся/удаляется класс, отнаследованный от базового T.
Наследники будут пользоваться обычными new/delete, но к ним также можно примешать BlockAlloc. Таким образом, мы легко и безопасно определяем, какие классы должны пользоваться пулами, не боясь сломать что-то в программе. Множественное наследование также прекрасно работает с этой примесью.

Готово. Наследуем Node от BlockAlloc и заново проводим тест.
Время теста теперь — 120 ms. В 5 раз быстрее. Но в c# аллокатор всё же лучше. Наверное, там не просто связный список. (Если же сразу после new сразу вызывать delete, и тем самым не тратить много памяти, умещая данные в кеш, получим 62 ms. Странно. В точности, как у .NET CLR, как будто он возвращает освободившиеся локальные переменные сразу в соответствующий пул, не дожидаясь GC)

2. Контейнер и его пёстрое содержимое

Часто ли попадаются классы, которые хранят в себе массу различных дочерних объектов, таких, что время жизни последних не дольше времени жизни родителя?

Например, это может быть класс XmlDocument, наполненный классами Node и Attribute, а также c-строками (char*), взятыми из текста внутри нод. Или список файлов и каталогов в файловом менеджере, загружаемых один раз при перечитывании каталога и больше не меняющихся.

Как было показано во введении, delete обходится дороже, чем new. Идея второй части статьи в том, чтобы память под дочерние объекты выделять в большом блоке, связанном с Parent-объектом. При удалении parent-объекта у дочерних будут, как обычно, вызваны деструкторы, но память возвращать не потребуется — она освободиться одним большим блоком.

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

Наконец, опишем примесь ChildObject с перегруженными new и delete, обращающимися к заданному аллокатору:

В этом случае кроме добавления примеси в child-класс необходимо будет также исправить все вызовы new (или воспользоваться паттерном «фабрика»). Синтаксис оператора new будет следующим:

new (… параметры для оператора… ) ChildObject (… параметры конструктора… )

Для удобства я задал два оператора new, принимающих A& или A*.
Если аллокатор добавлен в parent-класс как член, удобнее первый вариант:

Если аллокатор добавлен как предок (примесь), удобнее второй:

Понятно, что указатель и ссылка взаимно конвертируются, разделение этих случаев — избавления от лишних значков.

Для вызова delete не предусмотрен специальный синтаксис, компилятор вызовет стандартный delete (отмеченный *1), независимо от того, какой из операторов new был использован для создания объекта. То есть, синтаксис delete обычный:

Если же в конструкторе ChildObject (или его наследника) происходит исключение, вызывается delete с сигнатурой, соответствующей сигнатуре оператора new, использованном при создании этого объекта (первый параметр size_t будет заменён на void*).

Размешение оператора new в секции private защищает от вызова new без указания аллокатора.

Приведу законченный пример использования пары Allocator-ChildObject:

Заключение. Статья была написана 1.5 года назад для песочницы, но увы, не понравилась модератору.

Источник

Читайте также:  Чем отстирать полинявшую белую футболку
Оцените статью