Статическая или динамическая переменная? В стэке или в куче?
От: Kv1z  
Дата: 25.10.06 15:28
Оценка:
Господа, следующий вопрос:
Как написать функцию, которой в качестве параметра передаётся указатель на некую ячейку памяти, а она в соответсвии с тем принадлежит ли эта ячейка кучи или находиться в стэке "ведёт себя определённым образом" .
Т.е. вопрос сводится к такому виду:
Как определить, зная указатель на переменную, является ли переменна статической или была создана динамически во время выполнения программы?

void what_is(char *s)
{
 /*собственно код, пример которого хотелось бы увидеть*/
}

int _tmain(int argc, _TCHAR* argv[])
{
    char m[10]; // массив в стеке

    char *p; // указатель на динамически создаваемый массив
    p=(char*)malloc(10);

    //Следом идут два вызова "той саммой" функции
    what_is(&m[0]);
    what_is(p);

    return 0;
}


P.S. Если чё путаю в формулировках, плз, поправьте.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>

11.01.07 20:18: Перенесено модератором из 'C/C++' — Кодт
Re: Статическая или динамическая переменная? В стэке или в к
От: LaptevVV Россия  
Дата: 25.10.06 15:31
Оценка:
Здравствуйте, Kv1z, Вы писали:

K>Господа, следующий вопрос:

K>Как написать функцию, которой в качестве параметра передаётся указатель на некую ячейку памяти, а она в соответсвии с тем принадлежит ли эта ячейка кучи или находиться в стэке "ведёт себя определённым образом" .
K> Т.е. вопрос сводится к такому виду:
K>Как определить, зная указатель на переменную, является ли переменна статической или была создана динамически во время выполнения программы?

Вообще-то Скотт Мейерс об этом писал...
По бестиповому указателю — никак... Да и с типизированным — в общем случае — никак...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Статическая или динамическая переменная? В стэке или в к
От: MShura  
Дата: 25.10.06 15:37
Оценка:
K> Т.е. вопрос сводится к такому виду:
K>Как определить, зная указатель на переменную, является ли переменна статической или была создана динамически во время выполнения программы?

Это можно сделать только платформо зависимым способом.
Например под Windows берешь файлы vmquery.h(cpp) из главы 14 книжки Рихтера
и пользуешься его функцией VMQuery.

С её помощью можно ответить на вопрос стек или не стек.
Re: Статическая или динамическая переменная? В стэке или в к
От: Murom Россия  
Дата: 26.10.06 11:02
Оценка:
Здравствуйте, Kv1z, Вы писали:

K>Господа, следующий вопрос:

K>Как написать функцию, которой в качестве параметра передаётся указатель на некую ячейку памяти, а она в соответсвии с тем принадлежит ли эта ячейка кучи или находиться в стэке "ведёт себя определённым образом" .
K> Т.е. вопрос сводится к такому виду:
K>Как определить, зная указатель на переменную, является ли переменна статической или была создана динамически во время выполнения программы?

Задача не имеет решения.
Например я пишу свой менеджер памяти, который на стеке выделяет кусок памяти, а при динамичеси выделении делает placement new на стек.

Итог:
Это на стеке — ДА
Это динамически во время выполнения программы — ДА
- Eugeny
Re: Статическая или динамическая переменная? В стэке или в к
От: Kv1z  
Дата: 26.10.06 16:07
Оценка:
Народ, должно же быть как-то проще!? Адреса же разные, как узнать нужный диапазон? Место где куча начинается, стек?

void what_is(char *s)
{
 *s=1;
 printf("\ns=%p",s);
}

int _tmain(int argc, _TCHAR* argv[])
{
    char mas[1000];
    char *p;
    p=(char *)malloc(2);
    printf("\n&mas[0]=%p",&mas[0]);
    printf("\np=%p",p);
    what_is(&mas[0]);
    what_is(p);
    getch();
    return 0;
}
Результат работы:
&mas[0]=0012FB78
p=00357900
s=0012FB78
s=00357900
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Статическая или динамическая переменная? В стэке или
От: MShura  
Дата: 26.10.06 17:02
Оценка:
K>Народ, должно же быть как-то проще!? Адреса же разные, как узнать нужный диапазон? Место где куча начинается, стек?

на каких-то платформах стек растет в сторону больших адресов, на каких-то в сторону меньших.
На третьих стеков может быть несколько (обычно разные DSP).
Так что это все платформо зависимо. Для Windows 9x/2k+ на X86 решение приведено, а судя по результатам примера у тебя Windows.
Re[2]: Статическая или динамическая переменная? В стэке или
От: rm822 Россия  
Дата: 26.10.06 21:08
Оценка:
Здравствуйте, Kv1z, Вы писали:

K>Народ, должно же быть как-то проще!? Адреса же разные, как узнать нужный диапазон? Место где куча начинается, стек?


K>
K>void what_is(char *s)
K>{
K> *s=1;
K> printf("\ns=%p",s);
K>}

K>int _tmain(int argc, _TCHAR* argv[])
K>{
K>    char mas[1000];
K>    char *p;
K>    p=(char *)malloc(2);
K>    printf("\n&mas[0]=%p",&mas[0]);
K>    printf("\np=%p",p);
K>    what_is(&mas[0]);
K>    what_is(p);
K>    getch();
K>    return 0;
K>}
K>
Результат работы:

K>
K>&mas[0]=0012FB78
K>p=00357900
K>s=0012FB78
K>s=00357900
K>


как правильно сказали, VirtualQueryEx и рихтер

есть еще один непереносимый выриант

запись о базах стека есть в TIB
typedef struct _NT_TIB {
    struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;
    PVOID StackBase;
    PVOID StackLimit;
    PVOID SubSystemTib;
    union {
        PVOID FiberData;
        DWORD Version;
    };
    PVOID ArbitraryUserPointer;
    struct _NT_TIB *Self;
} NT_TIB;


получить указатель на TIB текущего потока вот так, если тебе хватит текущего потока то вполне сойдет
PNT_TIB        DebugSys::NtCurrentTIB()
{
    typedef VOID* (__stdcall *FnNtCurrentTeb)(void);
    static FnNtCurrentTeb    fnNtCurrentTeb = 
        (FnNtCurrentTeb)GetProcAddress(GetModuleHandle("NTDLL.DLL"),"NtCurrentTeb");
    return (PNT_TIB)(fnNtCurrentTeb)();
};


я когда-то залазил в исходники винды, оказывается можно извратиться и получить TIB по хэндлу потока
    PNT_TIB        GetTIB()
    {
        DESCRIPTOR_TABLE_ENTRY    dte = {0};
        dte.selector = 0x3B;
        ZwQueryInformationThread(
            m_hThread, 
            6,/*ThreadDescriptorTableEntry*/
            &dte,
            sizeof(dte),
            NULL);
        return     (PNT_TIB)(
                ((ptrdiff_t)dte.ldtEntry.BaseLow) + 
                (((ptrdiff_t)dte.ldtEntry.HighWord.Bits.BaseMid) << 16) + 
                (((ptrdiff_t)dte.ldtEntry.HighWord.Bits.BaseHi) << 24));
    }
    
typedef struct _DESCRIPTOR_TABLE_ENTRY {
    ULONG        selector;
    LDT_ENTRY    ldtEntry;
} DESCRIPTOR_TABLE_ENTRY, *PDESCRIPTOR_TABLE_ENTRY;



Непереносимо, но познавательно
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[3]: Статическая или динамическая переменная? В стэке или
От: Сергей Мухин Россия  
Дата: 27.10.06 03:20
Оценка:
Здравствуйте, rm822, Вы писали:


R>получить указатель на TIB текущего потока вот так, если тебе хватит текущего потока то вполне сойдет

R>
R>PNT_TIB        DebugSys::NtCurrentTIB()
R>


R>я когда-то залазил в исходники винды, оказывается можно извратиться и получить TIB по хэндлу потока

R>
R>    PNT_TIB        GetTIB()

R>



ну и загнули , TIB текущего thread сидит по FS: т.е. достаточно что-то вроде этого:

__declspec(naked) PNT_TIB gettib() {
__asm mov eax, fs
__asm ret
}
---
С уважением,
Сергей Мухин
Re[3]: Статическая или динамическая переменная? В стэке или
От: Сергей Мухин Россия  
Дата: 27.10.06 03:26
Оценка:
Здравствуйте, rm822, Вы писали:

ну и загнули , TIB текущего thread сидит по FS: т.е. достаточно что-то вроде этого:


__declspec(naked) void* getBaseStack gettib() {
__asm mov eax, fs:[4]
__asm ret
}

__declspec(naked) void* getLimitStack gettib() {
__asm mov eax, fs:[8]
__asm ret
}
---
С уважением,
Сергей Мухин
Re[4]: Статическая или динамическая переменная? В стэке или
От: rm822 Россия  
Дата: 27.10.06 06:05
Оценка:
Здравствуйте, Сергей Мухин, Вы писали:

СМ>Здравствуйте, rm822, Вы писали:


СМ>ну и загнули , TIB текущего thread сидит по FS: т.е. достаточно что-то вроде этого:



СМ>
СМ>__declspec(naked) void* getBaseStack gettib() {
СМ>__asm mov eax, fs:[4]
СМ>__asm ret
СМ>}

СМ>__declspec(naked) void* getLimitStack gettib() {
СМ>__asm mov eax, fs:[8]
СМ>__asm ret
СМ>}
СМ>


Спасибо я в курсе, только вот он там не сидит а мэпиться
метод с функциями был выбран намеренно, pTIB->StackBase, согласитесь, более выразительно чем mov StackBase,fs:[4]
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Если кому ещё интересно
От: remark Россия http://www.1024cores.net/
Дата: 28.12.06 01:36
Оценка:
Здравствуйте, Kv1z, Вы писали:

K>Господа, следующий вопрос:

K>Как написать функцию, которой в качестве параметра передаётся указатель на некую ячейку памяти, а она в соответсвии с тем принадлежит ли эта ячейка кучи или находиться в стэке "ведёт себя определённым образом" .


int* g_stack_begin; // Здесь начало стека
 
void f(int* p)
{
    int local_stack; // Здесь текущая позиция в стеке
    if (p < g_stack_begin && p > &local_stack)
        std::cout << "stack" << std::endl;
    else
        std::cout << "heap" << std::endl;
}

int main()
{
    // Инициализируем начало стека
    int stack_begin;
    g_stack_begin = &stack_begin;

    int iii;
    f(&iii);
    int* ppp = new int;
    f(ppp);
}



На многих платформах будет работать. Где то надо будет заменить ">" на "<" и "<" на ">".


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Статическая или динамическая переменная? В стэке или в к
От: Sm0ke Россия ksi
Дата: 28.12.06 11:31
Оценка:
Можно перегрузить оператор new для своего класса.
Там хранить вектор указателей, которые он выделяет.
Если указатель в векторе, то объект создан через new
Не забудте при delete удалять указатель из вектора.

Все остальные классы наследовать от того.


class base
{
private:
  static vector<void *> items;
public
  void * operator new(size_t size)
  {
    void * h= ::operator new(size);
    items.push_back(h);
    return h;
  }

  void operator delete(void * h)
  {
    // удаляем h из вектора
    ::operator delete(h);
  }

  static bool is_dynamic(void * h)
  {
    return /* проверяем, есть ли он в векторе */;
  }
};


Про malloc ничего не скажу пока
Re[2]: Если кому ещё интересно
От: johny5 Новая Зеландия
Дата: 29.12.06 14:03
Оценка:
Не забудьте про многопоточность. Система выделяет каждому потоку отдельный стек.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.