Custom assert.cpp/.h clashing with avr-gcc's assert?

I’m implementing my own assert() macro, for Arduino UNO.
It works ok when I put the files assert.cpp/.h into a dedicated lib/ subdirectory, but does not work if I put those same files in src/ and include/ dirs respectively. Why is that?

FAILS (gets stuck without printing the assert message)

.
├── include
│   └── assert.h
├── lib
│   ├── ADS1256
│      ├── ads1256.cpp
│      ├── ads1256.h
│      └── ads1256_regmap.h
├── src
    ├── assert.cpp
    └── main.cpp

WORKS (prints assert message correctly every time)

├── include
├── lib
│   ├── ADS1256/
│   ├── Assert/
│       ├── assert.cpp
│       └── assert.h
├── src
    └── main.cpp
  1. My theory is that it is somehow clashing with the default assert() macro provided in avr-gcc toolchain. If it is true, how can I prove it?
  2. Is it always a bad idea to implement assert functionality with the same name?
  3. Should I be using the avr-gcc provided assert? Where is it define and how? How to define what happens on assert failure?

For the interested, here is my assert.cpp/.h implementation:

#ifndef _ASSERT_H_
#define _ASSERT_H_

void assertion_failure(const char* expr, const char* file, int linenum);
#define assert(expr) \
    if (expr) ; \
    else assertion_failure(#expr, __FILE__, __LINE__)
#endif /* _ASSERT_H_ */
#include "assert.h" 
#include "Arduino.h"

void assertion_failure(const char* expr, const char* file, int linenum)
{
    Serial.print("Assertion failed in '");
    Serial.print(file);
    Serial.print("' on line ");
    Serial.print(linenum);
    Serial.print(": ");
    Serial.println(expr);
    Serial.flush();

    while (1);
}

AVR-LIBC has assert.h and the assert macro as documented in avr-libc. So not directly the compiler but the C library it uses.

As you can see in avr-libc: assert.h Source File and here

However I don’t see how this is modifyable if it needs to be modified. If the macro __ASSERT_USE_STDERR is set, it will attempt to call into fprintf() to print the error message. Additional syscall implementation has to be made to redirect that to Serial, see here and here for redirecting stdout and stderr.

This is expected. Files in the include/ folder of the project are by default not seen within libraries. Thus when your library does #include <assert.h> it gets avr-libc’s version of assert(), which, since I don’t see __ASSERT_USE_STDERR being defined, does a call to abort() if the assertion fails, hanging up. You can use build_flags to expose the include folder to all libraries, e.g. with build_flags = -Iinclude/ in the platformio.ini.

Correct, since now assert.h is seen as coming from that library, and libraries can see other libraries and their include files just fine.

However I suggest you not name your assert also assert.h as there is ambiguity then.

1 Like

Thank you, this explains it really well!