Longjmp
setjmp/longjmp to mechanizm umożliwiający niskopoziomową kontrolę sterowania w języku C bez uciekania się do asemblera. Może być używany np. do implementacji wyjątków.
Użycie
Należy wywołać funkcję setjmp z argumentem wskazującym bufor skoku.
Funkcja wróci zwracając wartość 0. Następnie jeśli użyjemy funkcji longjmp podając jej jako argumenty bufor skoku i wartość do zwrócenia, sterowanie zostanie przekazane ponownie do miejsca powrotu odpowiadającej funkcji setjmp:
jmp_buf jbuf;
void foo()
{
if (setjmp(jbuf) != 0)
{
printf("world!\n");
} else {
printf("Hello, ");
longjmp(jbuf, 1);
}
}
W powyższym przykładzie wydrukowane zostanie Hello, world!\n.
Ponieważ często chcemy skakać pomiędzy funkcjami, bufor jest zwykle zmienną globalną.
Typ jmp_buf jest typem wskaźnikowym, więc do funkcji setjmp i longjmp przekazujemy jbuf nie &jbuf.
Bufor skoku staje się nieaktualny po wyjściu z funkcji, z której wywołaliśmy setjmp.
Nagłówki
int setjmp(jmp_buf env);
void longjmp (jmp_buf env, int val);
Funkcja jest opisana w standardzie POSIX.
Przykład
W poniższym przykładzie użyjemy funkcji setjmp i longjmp do implementacji tablic, które zwracają wyjątek w przypadku próby dostępu poza granice tablicy.
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
jmp_buf array_access_exception;
struct array *array_access_exception_base;
int array_access_exception_index;
struct array
{
int *data;
int size;
};
void alloc_array(struct array *array, int size)
{
array->data = malloc(sizeof(int) * size);
array->size = size;
}
int read_array(struct array *array, int offset)
{
if (offset < 0 || offset >= array->size)
{
array_access_exception_base = array;
array_access_exception_index = offset;
longjmp(array_access_exception, 1);
}
return array->data[offset];
}
void write_array(struct array *array, int offset, int value)
{
if (offset < 0 || offset >= array->size)
{
array_access_exception_base = array;
array_access_exception_index = offset;
longjmp(array_access_exception, 2);
}
array->data[offset] = value;
}
void copy_array(struct array *a, struct array *b, int cnt)
{
int i;
for(i=0; i<cnt; ++i)
write_array(b, i, read_array(a, i));
}
int main()
{
struct array a,b;
int asz, bsz, cnt;
int xretval;
if((xretval = setjmp(array_access_exception)) != 0)
{
fprintf(stderr, "Trying to %s at invalid offset %i of array %p\n",
(xretval == 1) ? "read" : "write",
array_access_exception_index,
array_access_exception_base);
return 1;
}
printf("Enter size of array a: ");
scanf("%d", &asz);
printf("Enter size of array b: ");
scanf("%d", &bsz);
printf("How many elements to copy: ");
scanf("%d", &cnt);
alloc_array(&a, asz);
alloc_array(&b, bsz);
copy_array(&a, &b, cnt);
return 0;
}
Próba użycia:
$ ./arrayexcept Enter size of array a: 15 Enter size of array b: 20 How many elements to copy: 11 $ ./arrayexcept Enter size of array a: 15 Enter size of array b: 20 How many elements to copy: 34 Trying to read at invalid offset 15 of array 0xbffff350
array_access_exception to adres aktualnego handlera wyjątku. array_access_exception_base i array_access_exception_index przechowują dodatkowe informacje zwracane przez wyjątek.
Wszystkie funkcje korzystające z tablic, takie jak copy_array, są o wiele prostsze niż funkcje, które sprawdzałaby jawnie granice tablicy.
Content Disclaimer
Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.
- The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
- There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
- It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
- Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
- Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.