доступ к содержимому пустого указателя, содержащего объект C ++ в C

Я делаю бинарные инструменты с DynamoRIO использование клиента C в программе C ++ хотя вам, вероятно, не нужно знать о DynamoRIO, чтобы ответить на мой вопрос. В настоящее время я обертываю функцию, которая имеет подпись:

virtual void foo(Klass& s)

И тогда в функции wrap я могу получить аргумент вызова этой функции (Klass& s) к пустому указателю (void *arg1). Мне нужно использовать этот аргумент (то есть доступ к полям, вызов методов), однако я не могу привести его к соответствующему указателю как Klass это класс C ++, и клиент, который я использую, находится в чистом C.

Когда я пытаюсь распечатать содержимое void* бросив его в size_t такие как:

printf("%zd\n", (size_t)arg1);

это дает мне 8-значный номер, такой как 25102856 Я думаю, это адрес памяти.

У меня вопрос, как я могу получить доступ к этому объекту в моей программе?

Просьба просить всю необходимую информацию, я открыт для всех идей.

1

Решение

Чтобы заставить это работать — определите обертки стиля C для методов получения и установки, как в этом примере:

Для вашего класса

class Klass {
public:
int getA() const;
void setA(int);
virtua int getB() const;
};

Определите структуры C, которые обертывают этот класс:

typedef int (*GetInt)(void*);
typedef void (*SetInt)(void*,int);
// and similar for other typesstruct KlassCInterface {
void* object;
GetInt getA;
SetInt setA;
GetInt getB;
};

extern "C" int getA(void* obj)
{
return static_cast<Klass*>(klassObj)->getA();
}
...
KlassCInterface* getCInterface(Klass* obj)
{
// malloc just in case your client want to use free()
KlassCInterface* retVal = (KlassCInterface*)malloc(sizeof(KlassCInterface));
retVal->object = obj;
retVal->getA = &getA;
...
return retVal;
}

Когда вы передаете данные void *, передайте их как структуру интерфейса C:

Klass* obj = new Klass(...);
KlassCInterface* objC = getCInterface(obj);

registerData(objC);

В вашем коде C — используйте этот интерфейс C:

void doSthWihtKlass(void* data)
{
KlassCInterface* objC  = (KlassCInterface*)data;
printf("%d\n", objC->getA(objC->object));
}
3

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

Это должно быть трудно сделать. Вы должны будете знать о базовом C ++ ABI. G ++ реализует этот.

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

Обратите внимание, что ничего из этого не решается в соответствии с ISO 14882. Возникновение этого, безусловно, вызывает неопределенное поведение.

Что касается вызова виртуальных методов, вам придется искать v-таблицу. Еще раз, изучите ABI у вашего компилятора.

1

Вам нужно больше узнать о семантике указателя (и это то, что, я думаю, имел в виду @Alek).

Прежде всего, вы можете использовать %p спецификатор формата printf для прямой печати указателей. Это обычно приводит к некоторому полезному значению, такому как место в памяти, на которое указывает указатель.

Вы можете привести указатель к char * и использовать его для чтения байтов непосредственно из памяти. Или вы можете привести его к unsigned char * и сделать «шестнадцатеричный дамп», используя %x, Вы можете привести его к int * и прочитайте целое число, как представлено вашей реализацией C — например, возможно, 4-байтовое 2 дополняет целое число со знаком с прямым порядком байтов в 8-битных байтах без неиспользуемых битов, например.

((unsigned long *)(((short *) ptr) + 7))[4] например, пропустит количество байтов, равное размеру 7 шорт плюс 4 длинных без знака, и прочитает длинный без знака из ячейки памяти. Предполагая правильное представление (как ожидает реализация C) unsigned long был записан в эту точную ячейку памяти, вы получите его значение.

Вы не только должны быть уверены, что именно написано, где в памяти указано ptr (именно поэтому был упомянут ABI), но и получающаяся в результате программа будет непереносимой и может изменяться / прерываться по желанию.

Вам также могут понадобиться целочисленные типы с точной шириной, как указано в <inttypes.h> заголовок.

1
По вопросам рекламы [email protected]