In sviluppo embedded, quando si ha per esempio un vettore di puntatori di interruzione, è molto utile per essere in grado di utilizzare il collegamento debole per ottenere gestori predefiniti per gli interrupt che non sei interessato a.
Questo funziona definendo un gestore vuoto (una sola volta), quindi introducendo un nuovo simbolo opportunamente nominato per ogni puntatore di interrupt di cui hai bisogno, che è debolmente collegato al gestore predefinito.
Il vettore viene quindi riempito con questi simboli, che puntano tutti allo stesso codice effettivo, finché non si decide di implementare uno di essi utilizzando lo stesso nome (corretto), quindi il codice "soprapassa" il collegamento debole, causando un puntatore al codice da installare nella tabella degli interrupt.
questo è spesso implementato in un misto di C e di assemblaggio, ma utilizzando C pseudocodice potremmo avere qualcosa di simile:
static void placeholder_isr(void)
{
}
/* Introduce properly-named function pointers, with weak linking.
* NOTE: This syntax is completely fictional as far as I know.
*/
void (*timer1_isr)() = placeholder_isr __attribute("weak linking");
void (*timer2_isr)() = placeholder_isr __attribute("weak linking");
void (*usart1_isr)() = placeholder_isr __attribute("weak linking");
void (*usart2_isr)() = placeholder_isr __attribute("weak linking");
void (*dma1_isr)() = placeholder_isr __attribute("weak linking");
void (*dma1_isr)() = placeholder_isr __attribute("weak linking");
/* Declare the table of interrupt handlers. */
static void (*isr_table)[] = {
timer1_isr,
timer2_isr,
usart1_isr,
usart2_isr,
dma1_isr,
dma2_isr,
} __attribute("isr vector"); /* Attribute to place it where it needs to go. */
Poi si può solo implementare la propria funzione in caso di necessità:
void timer1_isr(void)
{
/* Handler ISR from timer1. */
}
senza dover cambiare altro, "funziona". Finché il tuo nome è quello che il "codice di supporto" di cui sopra si aspetta, ovviamente.
https://ofekshilon.com/2014/02/10/linker-weak-symbols/ –