Weak functions cost me a few hours of debugging

Weak symbols are relatively common in embedded systems.

I’m going to mostly ignore the use of weak variables and focus on weak functions. Mostly because while weak symbols are interesting I don’t have much experience with them and I’m not really sure why you would want to use them.

Weak functions are typically used to provide a default implementation of a function while also providing the developer with the ability to easily override this function with their own.

C++ provides virtual methods for this purpose:

class BaseClass
{
public:
  virtual void DoSomething() { /* stub */ }
};

...

class MyClass : public BaseClass
{
public:
  void DoSomething() override { take_some_action(); }
};

For C another technique could be to use function pointers:


// library.c

typedef void(*fn)(void);

void default_function() { // stub }

static fn callback = default_function;

void SomeInternalLibraryCall()
{
    // do stuff

    callback();

    // do more stuff
}

void SetCallback(fn new_fn)
{
    callback = new_fn;
}

...

// and in your code

void my_callback()
{
    // take some action
}

void my_init()
{
  SetCallback(my_callback);
  SomeInternalLibraryCall();
}

If you are using C, weak functions are simpler than callbacks.


// in library.c

// Declare a weak function
void __attribute__((weak)) some_weak_function(void) {
    printf("This is the weak function.\n");
}

void SomeInternalLibraryCall()
{
    some_weak_function();
}

...

// in your code

void some_weak_function(void)
{
    printf("This will be printed instead\n");
}


int main() {
    SomeInternalLibraryCall();

    return 0;
}

So weak functions are pretty cool except when they aren’t.

What if your code tries to override the weak function like this:

void someweak_function(void)
{
    printf("The function name doesn't match exactly.\n");
    printf("So you'll spend a few hours debugging and trying to figure out\n");
    printf("Why your function isn't being called, until you spot the typo...\n");
}

This function will compile correctly. You might get a warning about ‘someweak_function’ being unused, which could save your

As far as I can tell there is no equivalent to C++’s ‘override’ keyword for weak functions.

There isn’t a mechanism to say “Compiler, I’m overriding a weak function here, let me know if you don’t know of a weak function to override to save me from hours of debugging due to a typo.”

So be careful when using weak functions and when debugging them make sure that your names matched up exactly.

In my particular case I got caught by the STM32 HAL library. There was a weak function:

__weak void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef *hdac)
...

I needed the second channel so I replaced the ‘1’ with ‘2’ and used:

// THIS NAME IS INCORRECT, don't copy!
void HAL_DAC_ConvCpltCallbackCh2(DAC_HandleTypeDef *hdac) { my_code_here; }

but this isn’t the name… the name was actually:

__weak void HAL_DACEx_ConvCpltCallbackCh2(DAC_HandleTypeDef *hdac)

Doh… A couple of hours cleaning some test cases up and running under gdb without hitting the expected breakpoints and I went through the library source code and spotted the different name. I’m not sure how much longer it might have taken to debug if I had kept going with the incorrect assumption that I was overriding the proper function.

Updated: