Re[2]: Насколько корректно использовать адрес переменной в стеке
От: kov_serg Россия  
Дата: 20.07.17 07:22
Оценка:
Здравствуйте, icWasya, Вы писали:

W>Здравствуйте, Nick-77, Вы писали:


W>...


N7>>т.е. вроде как несмотря на то, что формально tmp и её адреса после выхода из f не существует, реально стек ещё никто не успел (?) испортить и содержимое верное.



N7>>Хотелось бы узнать у господ знатоков, насколько корректно подобное допущение.

Еще бывает что стек растёт в другую сторону на некоторых архитектурах.
  Скрытый текст
// ptsk.h : popup multitasking
#ifndef __PTSK_H__
#define __PTSK_H__

#include <setjmp.h>
#include "ticks.h"                   // any real time clock

#ifdef __cplusplus
extern "C" {
#endif

typedef struct ptsk_tcb_tag {
    void (*task)(void*);
    void *args;
    int   stack_size;
    jmp_buf ctx;
    struct ptsk_tcb_tag* next;
    struct ptsk_tcb_tag* prev;
} ptsk_tcb_t;

void ptsk_init(void);
void ptsk_done(void);
void ptsk_idle(void);                // give control to next task
void ptsk_addtask(ptsk_tcb_t *task); // create new task
void ptsk_deltask(ptsk_tcb_t *task); // if current it'll die
void ptsk_die(void);                 // kill current task
ptsk_tcb_t* ptsk_getcurrent();       // get current task descriptor
extern int ptsk_active;

void ptsk_sleep(ticks_t ticks);
void ptsk_sleep_till(ticks_t time);

/*

usage:

#include <stdio.h>
#include "ptsk.h"

void task1(void* arg) {
    for(int i=0;i<=9;++i) {
        printf("task1 \ti=%d\n",i);
        ptsk_idle();
    }
}
void task2(void* arg) {
    for(int i=0;i<=7;++i) {
        printf("task2 \t\ti=%d\n",i);
        ptsk_sleep(500);
    }
}
void task3(void* arg) {
    for(int i=0;i<=5;++i) {
        printf("task3 \t\t\ti=%d\n",i);
        ptsk_sleep(1000);
    }
}

ptsk_tcb_t t1={task1,(void*)1,1024};
ptsk_tcb_t t2={task2,(void*)2,1024};
ptsk_tcb_t t3={task3,(void*)3,1024};

void main() {
    ptsk_init();
    ptsk_addtask(&t1);
    ptsk_addtask(&t2);
    ptsk_addtask(&t3);
    ptsk_idle();
    ptsk_done();
}

*/

#ifdef __cplusplus
}
#endif

#endif // __PTSK_H__

// ptsk.c
#include "ptsk.h"

#ifdef __cplusplus
extern "C" {
#endif

enum {
    PTSK_1ST =0,
    PTSK_WAKE=1,
    PTSK_NEW =2,
    PTSK_RET =3
};

int         ptsk_active=0;
ptsk_tcb_t* ptsk_head;
ptsk_tcb_t* ptsk_tail;
ptsk_tcb_t* ptsk_curr;
jmp_buf     ptsk_last;
jmp_buf     ptsk_main;

void ptsk_init(void) {
    ptsk_active=0;
    ptsk_head=ptsk_tail=ptsk_curr=0;
}
void ptsk_done(void) {
    if (ptsk_active) longjmp(ptsk_main,PTSK_RET);
}
void ptsk_panic(void) {
    // exit(0);
    for(;;) {}
}
void ptsk_switch(void) {
    ptsk_curr=ptsk_curr->next;
    if (!ptsk_curr) {
        ptsk_curr=ptsk_head;
        if (!ptsk_curr) ptsk_done();
    }
    longjmp(ptsk_curr->ctx,PTSK_WAKE);
}
void ptsk_die(void) {
    if (!ptsk_curr) { ptsk_done(); ptsk_panic(); return; } // panic
    if (ptsk_curr->prev) ptsk_curr->prev->next=ptsk_curr->next; else ptsk_head=ptsk_curr->next;
    if (ptsk_curr->next) ptsk_curr->next->prev=ptsk_curr->prev; else ptsk_tail=ptsk_curr->prev;
    ptsk_switch();
}
void ptsk_deltask(ptsk_tcb_t *task) {
    if (ptsk_curr==task) ptsk_die();
    if (task->prev) task->prev->next=task->next; else ptsk_head=task->next;
    if (task->next) task->next->prev=task->prev; else ptsk_tail=task->prev;
}
int ptsk_stackalloc(int arg) {
    volatile int dummy; ptsk_tcb_t* tsk; int sz;
    static int* stk;
    if (arg==1) stk=(int*)&dummy;
    sz=(int*)&dummy-stk; if (sz<0) sz=-sz;
    if (sz<ptsk_tail->stack_size) ptsk_stackalloc(0);
    tsk=ptsk_tail;
    if (setjmp(ptsk_last)==PTSK_NEW) ptsk_stackalloc(1);
    switch(setjmp(tsk->ctx)) {
        case PTSK_1ST:  longjmp(ptsk_main,PTSK_RET);
        case PTSK_WAKE: tsk->task(tsk->args);
    }
    ptsk_die(); return dummy;
}
void ptsk_addtask(ptsk_tcb_t *task) {
    ptsk_tcb_t* last;
    last=ptsk_tail;
    task->prev=ptsk_tail;
    task->next=0;
    if (ptsk_tail) ptsk_tail->next=task; else ptsk_head=task;
    ptsk_tail=task;
    switch(setjmp(ptsk_main)) {
        case PTSK_1ST:  if (last) longjmp(ptsk_last,PTSK_NEW); else ptsk_stackalloc(1);
        //case PTSK_RET: break;
    }
}
void ptsk_idle(void) {
    if (!ptsk_curr) {
        ptsk_curr=ptsk_head; if (!ptsk_curr) return;
        ptsk_active=1;
        switch(setjmp(ptsk_main)) {
            case PTSK_1ST: ptsk_curr->task(ptsk_curr->args); ptsk_die();
            //case PTSK_RET: break;
        }
        ptsk_active=0;
        return;
    }
    switch(setjmp(ptsk_curr->ctx)) {
        case PTSK_1ST:  ptsk_switch();
        //case PTSK_WAKE: break;
    }
}
ptsk_tcb_t* ptsk_getcurrent() {
    return ptsk_curr;
}
void ptsk_sleep_till(ticks_t time) {
    do {
        ptsk_idle();
    } while(time-getticks()>0);
}
void ptsk_sleep(ticks_t ticks) {
    ptsk_sleep_till(getticks()+ticks);
}

#ifdef __cplusplus
}
#endif

W>Если после выхода из функции произойдёт прерывание , то его обработчик всё затрёт .
Это только не в защищённых режимах такая фигня. Бывает
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.