2

I have a very simple routine that lights up the built-in LED (pin 13) when a system tick timer fires off its interrupt.

I override the weak reference to int sysTickHook(void) found in hooks.c. I found that in generalfor this to work I need to use extern "C" linkage

The part that is bewildering is that this interrupt fires off fine without extern "C" if there are the comments above it as shown below. This is the minimal reproducible example I can find. Can someone explain this?

I'm using the plain old Arduino IDE 1.8.16.

void setup() {
  pinMode(13,OUTPUT);  
  digitalWrite(13,LOW);
}

void loop() {}

// {          -- if you remove this line sysTickHook will not be called
// extern "C" -- if you remove this line sysTickHook will not be called
int sysTickHook()
{        
  digitalWrite(13,HIGH);
  return 0;
}
4
  • It's probably the function prototypes the IDE puts in that're breaking it.
    – Majenko
    Commented Oct 14, 2021 at 19:46
  • How would those be affected by the presence of a comment? Commented Oct 14, 2021 at 19:57
  • I would look into it further, but if I were going to put the effort into that I'd want to know what board support package you were using and what board was selected.
    – timemage
    Commented Oct 14, 2021 at 20:54
  • @timemage I havn't installed anything third party nor modified any of the installed libraries. I added via the board manager "Arduino SAM boards 1.6.12". To compile and upload I am just using the "Arduino Due (Programming Port)" drop down. The verbose compiation says Using board 'arduino_due_x_dbg' from platform What other info can I provide? Commented Oct 14, 2021 at 21:07

1 Answer 1

2

The problem is the preprocessor in the IDE. It's not clever enough to work out the extern "C" when adding function prototypes.

With your comments you end up with:

#include <Arduino.h>
#line 1 "/home/matt/t/t.ino"
#line 1 "/home/matt/t/t.ino"
void setup();
#line 6 "/home/matt/t/t.ino"
void loop();
#line 10 "/home/matt/t/t.ino"
 extern "C" int sysTickHook(); // << The extern gets added here from the comment
#line 1 "/home/matt/t/t.ino"
void setup() {
  pinMode(13,OUTPUT);  
  digitalWrite(13,LOW);
}

void loop() {}

// {          -- if you remove this line sysTickHook will not be called
// extern "C" -- if you remove this line sysTickHook will not be called
int sysTickHook()
{        
  digitalWrite(13,HIGH);
  return 0;
}

It finds the extern in the comment and thinks it's real code. If you remove the comment markers it ends up with broken code, as you have a stray { in there. If you remove the comments entirely you end up with the function in the C++ linkage, which changes the function name internally and doesn't then override the weak function. The same happens if you remove just the first comment.

Basically having those comments breaks the preprocessor in such a way that it works. The proper way of doing it is:

void setup() {
  pinMode(13,OUTPUT);  
  digitalWrite(13,LOW);
}

void loop() {}

extern "C" {
  int sysTickHook()
  {        
    digitalWrite(13,HIGH);
    return 0;
  }
}
3
  • Treating comments as code is a pretty huge bug! Can the Arduino IDE preprocessor really be broken in this way? Commented Oct 14, 2021 at 22:01
  • 1
    @AdamV.Steele Sure it can. It's less broken than it used to be - it used to even put the prototypes in completely the wrong place and broke any attempt at using structs as parameters.
    – Majenko
    Commented Oct 14, 2021 at 22:29
  • @AdamV.Steele, lol, welcome to Arduino.
    – timemage
    Commented Oct 14, 2021 at 22:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.