7

I need to write some algorithms for a PIC micro controller. AFAIK, the official tools support either assembler or a subset of C.

My goal is to write the algorithms in a generic and reusable way without losing any runtime or memory performance. And if possible, I would like to do this without increasing the development time much and compromising the readability and maintainability much either.

What I mean by generic and reusable is that I don't want to commit to types, array sizes, number of bits in a bit field etc. All these specifications, IMHO, point to C++ templates, but there's no compiler for it for my target. C macro metaprogramming is another option, but, again my opinion, that greatly reduces readability and increases development time.

I believe what I'm looking for is a decent C++ to C translator, but I'd like to hear anything else that satisfies the above requirements. Maybe a translator from another high-level language to C that produces very efficient code, maybe something else.

Please note that I have nothing against C, I just wish templates were available in it.

5
  • 2
    Comeau C++ is a C++ compiler that works as a front-end for an existing C compiler. You could contact them to see if they have a C++ front-end for your existing C compiler. Commented Nov 11, 2013 at 7:22
  • Which PIC? There is now a C++ compiler for some of them, if you're that way inclined.
    – detly
    Commented Nov 12, 2013 at 2:15
  • @Bart Comeau C++ looks promising, I'll check back when their site is not under construction.
    – enobayram
    Commented Nov 12, 2013 at 4:08
  • LLVM can ostensibly output C as a target, so in theory you could use Clang++ to compile C++ to C. In practice I don't know how well the C backend actually works (when I tried it a couple of versions ago it was broken and generated rubbish). Commented Mar 4, 2014 at 22:12
  • @enobayram: It's not just some random C++ compiler. Many C++ papers mention Comeau C++ as a de-facto reference or kind thereof. They are just off-pace regarding their website. It's itself based on the EDG-C++ frontend, which have several members being integral parts of C++ standardization, and authors of great books. But I agree, it looks strange atm.
    – phresnel
    Commented Nov 13, 2014 at 10:38

2 Answers 2

20

Unless you have at least 3 use-cases where the algorithms will be used with different types and sizes, you are not going to do good job of the genericity anyway. So don't bother too much.

I'd recommend writing it in plain C using custom typedefs for all types (except things that are obviously size_t, int or such) and #defines for any relevant sizes. Than you can adjust the algorithms easily by changing those definitions. You can put the definitions in one header that you can easily override for the use-cases.

You can also use the C's poor man's template system, the preprocessor. Like define a macro, that will get a type and expand to definition of the function for that type. Or define the parameters to expand, include a header/source to define the functions and undefine the parameters again. The later does not convolute diagnostics as much and is probably easier to manage.

Something like:

  • sort.h:

     void sort_##SORT_TYPE(SORT_TYPE *begin, SORT_TYPE *end);
    

    IIRC you'll need some wrapper macro to get the definition expanded appropriate number of times.

  • sort.c:

     void sort_##SORT_TYPE(SORT_TYPE *begin, SORT_TYPE *end)
     {
         // whatever
         if(SORT_LESS(i, j)) // ...
         // ..
     }
    
  • using:

     #define SORT_TYPE int
     static inline int less(int x, int y) { return x < y; }
     #define SORT_LESS less
     #include "sort.h"
     #include "sort.c" // you only do this in a .c file
     #undef SORT_TYPE
     #undef SORT_LESS
    
5
  • 2
    +1 for "don't bother too much"
    – Javier
    Commented Nov 11, 2013 at 13:24
  • That's good and lightweight advice. I guess using typedefs in separate replacable headers instead of template arguments is a viable option at the scale that I'm planning to use it. And if I choose to migrate to actual templates later, the migration would be next to trivial.
    – enobayram
    Commented Nov 12, 2013 at 4:20
  • Did you know that the standard C library qsort() function is already polymorphic, using a completely different technique?
    – David Cary
    Commented Nov 19, 2014 at 23:17
  • 1
    @DavidCary: Sure I did. But the point is it is (runtime) polymorphic, not generic.
    – Jan Hudec
    Commented Nov 20, 2014 at 5:35
  • IMHO qsort is runtime generic not polymorphic. <T> size and comparison operator are passed at runtime in function parameters instead of template parameters, but they ARE still tied to T's semantics and not qsort's. In some ways this is more generic than templates since the same source code can be used as both a runtime generic and a compile time generic depending on how it is compiled and optimized. Commented Oct 12, 2021 at 3:00
1

The best way to handle this is to actually write your algorithms in a language independent pseudo code. Then, you can create a reference implementation in a language of choice, like C, carefully noting the edge cases that make this implementation tied to a particular memory model, data type model, byte sizes, bit handling capabilities, loop exit conditions weirdness ( think floating point ) types size overflow, etc. etc.

The reason this is a good strategy is that you will never achieve true portability with any known set of language tools, compilers, cross compilers, diagramers, prototypers. It is just not truly tractable.

Once you have created a few reference implementations, ideally in very diverse languages ( think Lisp or Prolog ) you will be able to more fully identify, understand and anticipate how your code will adapt to different platforms; and learn how to write pseudo code, move carefully toward an implementation and track the edge cases and dependencies.

You should maintain the artifacts as you go down this implementation path, as these, like the high level pseudo code will help you to architect an alternate reference implemenation, suited to an arbitrary future platform.

This approach lets you arbitrarily add and subtract dependencies , weighing their utility against their possible future lock-in effects. IE, if you decide to use a virtual memory subsystem , like the JVM, you will basically have to rewrite and refactor everything if you ever decide to implement the same pseudo code on an embedded processor....

1
  • 2
    Thanks for the advice, but I'm quite negatively disposed against writing first in pseudocode. Translating between programming languages (pseudo or not) is error-prone and time consuming. Not to mention it's bad for future maintenance and testing. IMHO it's the job of a compiler.
    – enobayram
    Commented Nov 12, 2013 at 4:14

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.