Пытаясь написать мелкую учебную програмку на С нашел способ не слабо усложнить решение, но тем не менее сделать его идеальным для образовательных целей. И так, код:
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>
using namespace std;
struct TestCase{
int ida;
int idb;
};
int main()
{
TestCase ** tests; //create pointer to pointer
cout << "Size of TestCase: " << sizeof(TestCase) << endl;
tests = malloc(sizeof(TestCase*)*5);
if(tests == NULL)
exit(1);
for(int i=0; i< 5; i++)
{
tests[i] = malloc(sizeof(struct TestCase));
if(tests[i] == NULL)
exit(1);
}
cout << "*tests = " << *tests << endl;
for(int i = 0; i < 5; i++)
{
tests[i]->ida = i;
tests[i]->idb = i+6;
cout << std::hex << &(tests[i]->idb) << ": " << *(long*)((long)(long*)(tests[i])+(long)&(((TestCase *)NULL)->idb)) << endl;
}
for(int i=0; i<5; i++)
{
free(tests[i]);
}
cout << "*tests = " << *tests << endl;
free(tests);
return 0;
}
Вобщем, ничего страшного за исключением этой строчки:
*(long*)((long)(long*)(tests[i])+(long)&(((TestCase *)NULL)->idb))
Не буду долго глагольствовать, а просто сразу разберу её на составляющие. И так, эта строчка возвращает значение параметра idb элемента test[i]
Начнем разбираться с середины:
-
tests[i] - это значение указателя, тоесть адрес в памяти, по которому находится структура test[i] (вместо i подставляем 1,2,3,4,5).
-
(TestCase *)NULL
- Мы создаем временный указатель на структуру типа TestCase. Адрес по которому указывает этот парень NULL, или проще говоря - 0. -
((TestCase *)NULL)->idb)
- по этому адресу будет находиться значение параметра idb относительно указателя на структуру NULL. По скольку адрес указателя на структуру = 0, то очень легко узнать, как далеко от него будет находиться параметр структуры idb -
(long)&(((TestCase *)NULL)->idb)
- узнаем адрес параметра idb в NULL структуре. У меня 64 разрядный процессор, по этому я использую long, потому как int не хватает для хранения адресов такого процессора. Адрес idb относительно NULL структуры будет его смещением в структуре. Тоесть, во всех структурах типа TestCase в этой программе параметр idb будет находиться через такое количество байт относительно этой структуры, которое мы получим здесь. -
Узнаем адрес смещения параметра idb относительно нашего указателя на tests[i]:
(tests[i])+(long)&(((TestCase *)NULL)->idb))
-
Ну и финал - получим значение по смещению из предыдущего шага:
(long)((long)(long*)(tests[i])+(long)&(((TestCase *)NULL)->idb))