Compile-time checking of function arguments...

If I have a function that is often called with constants for arguments, like say:

   digitalWrite(int pin, int state);

I could consider writing a wrapper:

   static inline digitalWrite(unsigned int pin, int state) {
      if (__builtin_constant_p(pin) && pin > PIN_MAX) {
         compileTimeError("Invalid Pin number");
      }
      if (__builtin_constant_p(state) && !(state == INPUT || state == OUTPUT || state == INPUT_PULLUP)
         compileTimeError("Invalid Pin State");
      _digitalWrite_internal(pin, state);
   }

In the case where the arguments are constants, this will either generate an error at compile time when it can show meaningful error messages, or optimize down to zero code in the binary, so it has an upside but no apparent downside.
In the case where the arguments are not constants, it still optimizes down to nothing, and the function that already existed may or may not do it's own run-time error checking (but has more of a problem reporting the error.)

  • Is there some reason I shouldn't do this? I guess it becomes dependent on gcc-specific compiler features...
  • is there a way to get the compiler to do this sort of thing automatically? It seems like one of those things than C++ would jump on.

That is precisely how Teensyduino gains a huge boost for the digital I/O functions.

Paul Stoffregen handled all four cases fordigitalWrite. From what I could tell the gains for variable / constant and constant / variable are marginal and added a significant amount of code so I left them out of Tiny Core 2. If you think it would be helpful I may be able to find the discussion. As an added bonus a const array (think port addresses and bit numbers) is also optimized to simple constants when the index is a constant (Yeah GCC!).

In Tiny Core 2 I had a single array definition that was included in two places: 1. In the header file with the digital functions to be used by the inline digital functions; 2. In the CPP file with the “normal” digital functions. The definition in the header file was always optimized to simple constants because the array index was always a constant.

That sort of construct is a great way to explore speed / size trade-offs. For example, the digital I/O functions always reduce to less code for constant parameters (one or two machine instructions which is less than loading registers then making a call).

is there a way to get the compiler to do this sort of thing automatically?

I have a vague recollection of trying to automate the task using template but giving up.

In this case, I'm not talking about having the binaries "improved", or even changed at all. The only thing the added "constant case" code would do is range checking that would be eliminated by optimization anyway.

Ah. Got it.

Is there some reason I shouldn't do this?

I can't come up with a reason to avoid it. (Other than the one you mentioned.)

is there a way to get the compiler to do this sort of thing automatically?

I'm not seeing it.