Jeden trik, který není přenosný a dokonce ani zaručeně nefunguje, je jednoduchý tisk adresy místního jako ukazatele.
void print_stack_pointer() {
void* p = NULL;
printf("%p", (void*)&p);
}
Tím se v podstatě vytiskne adresa p
což je dobrá aproximace aktuálního ukazatele zásobníku
Neexistuje žádný přenosný způsob, jak to udělat.
V GNU C to může fungovat pro cílové ISA, které mají registr s názvem SP, včetně x86, kde gcc rozpoznává "SP" jako zkratku pro ESP nebo RSP.
// broken with clang, but usually works with GCC
register void *sp asm ("sp");
printf("%p", sp);
Toto použití proměnných místního registru je nyní GCC zastaralé:
Jediné podporované použití této funkce je specifikovat registry pro vstupní a výstupní operandy při volání Extended asm
Definování proměnné registru nerezervuje registr. Jinak než při vyvolání Extended asm není obsah zadaného registru zaručen. Z tohoto důvodu nejsou následující použití výslovně podporována. Pokud se zdá, že fungují, je to jen náhoda a může přestat fungovat, jak bylo zamýšleno kvůli (zdánlivě) nesouvisejícím změnám v okolním kódu nebo dokonce drobným změnám v optimalizaci budoucí verze gcc. ...
V praxi je to také narušeno s clang kde sp
se zachází jako s jakoukoli jinou neinicializovanou proměnnou.
Kromě odpovědi duedl0r konkrétně GCC můžete použít __builtin_frame_address(0)
který je specifický pro GCC (ale ne x86 konkrétní).
To by mělo fungovat i na Clangu (ale jsou v něm nějaké chyby).
Řešením je také adresa místního (jak odpověděl JaredPar).
Všimněte si, že AFAIK standard C teoreticky nevyžaduje žádný zásobník volání.
O jiné technice by se dalo snít. A mohli byste mít rozdělené zásobníky (alespoň na nedávném GCC), v takovém případě má samotný pojem ukazatel zásobníku mnohem menší smysl (protože zásobník není souvislý a mohl by se skládat z mnoha segmentů, každý o několika volacích rámcích) .