Author Topic: A C Macro that reference another macro  (Read 4827 times)

0 Members and 1 Guest are viewing this topic.

Offline jealcunaTopic starter

  • Contributor
  • Posts: 39
  • Country: ec
A C Macro that reference another macro
« on: November 02, 2021, 03:12:41 am »
I have the following macros:

(see attached picture)

I have a c variable uint8_t type and I would like to call these macros following each bit of the variable. So I wonder if there is an elegant way to accomplish this rather than use a if else for each bit.
 

Offline blacksheeplogic

  • Frequent Contributor
  • **
  • Posts: 532
  • Country: nz
Re: A C Macro that reference another macro
« Reply #1 on: November 02, 2021, 03:15:51 am »
Why not just pass the bit mask to the macro?
 

Offline golden_labels

  • Super Contributor
  • ***
  • Posts: 1207
  • Country: pl
Re: A C Macro that reference another macro
« Reply #2 on: November 02, 2021, 03:20:33 am »
Please post text as text, not a picture.

Also describe the problem properly. Currently you have posted some picture, containing defines that aren’t even macros taking arguments, yet you ask about something seemingly taking arguments, which is used in a way that you haven’t explained, then you ask how to achieve the effect you forgot to describe.

If you can’t form a description, at least show us a minimal piece of code that depicts such a macro being used.
People imagine AI as T1000. What we got so far is glorified T9.
 

Offline jealcunaTopic starter

  • Contributor
  • Posts: 39
  • Country: ec
Re: A C Macro that reference another macro
« Reply #3 on: November 02, 2021, 03:30:42 am »
For a moment assume that bitmask manipulation is not possible.

So this is a basic piece of code:

uint8_t variable;
...
variable = 2; // 0b00000010, only OUT_02_ON should be called, for the others OUT_0X_OFF
...

if(variable&1){
    OUT_01_ON;
}else{
    OUT_01_OFF;
}

if(variable&2){
    OUT_02_ON;
}else{
    OUT_02_OFF;
}

if(variable&4){
    OUT_03_ON;
}else{
    OUT_03_OFF;
}

...

if(variable&128){
    OUT_08_ON;
}else{
    OUT_08_OFF;
}

Is there a more elegant solution for this referencing macros?
« Last Edit: November 02, 2021, 03:32:39 am by jealcuna »
 

Offline ledtester

  • Super Contributor
  • ***
  • Posts: 3034
  • Country: us
Re: A C Macro that reference another macro
« Reply #4 on: November 02, 2021, 03:57:19 am »
What don't you like about your code?

Here's another idea - which you may or may not find acceptable:

Code: [Select]
switch (variable) {
  case 0:
    OUT_01_OFF;
    OUT_02_OFF;
    OUT_03_OFF;
    ...
    break;
  case 1:
    OUT_01_ON;
    OUT_02_OFF;
    OUT_03_OFF;
    ...
    break;
  case 2:
    OUT_01_OFF;
    OUT_02_ON;
    OUT_03_OFF;
    ...
    break;
  ...253 more case statements...
}

All of this code can be generated by a program so you don't have to type it in.
 

Offline golden_labels

  • Super Contributor
  • ***
  • Posts: 1207
  • Country: pl
Re: A C Macro that reference another macro
« Reply #5 on: November 02, 2021, 02:47:11 pm »
In the presented code macros are not used in any way, that would be related to the question. You are invoking them, but they have nothing to do with how variable is used or you have failed to explain that connection. So for now I am ignoring the subject of macros, unless you clarify what did you mean.

The more elegant way to do that may be to use bit shifts in a loop, which you have refused to use for some reason (possibly XY problem?). An alternative approach might be a look-up table. But if any of those is suitable for your particular purpose depends on what you actually want to achieve. It’s possible that the problem is how variable is structured, preventing you from using a better solution.

We’re missing the definitions of OUT_… macros, but it seems you are using object-like macros to generate runtime code. That is confusing to the reader. Consider turning them into function-like macros: to make it clear you are executing something at runtime. There is also a hard to ignore chance of two more mistakes: silently referring to the local context and using macros instead of functions.
« Last Edit: November 02, 2021, 02:49:02 pm by golden_labels »
People imagine AI as T1000. What we got so far is glorified T9.
 

Offline Jeroen3

  • Super Contributor
  • ***
  • Posts: 4078
  • Country: nl
  • Embedded Engineer
    • jeroen3.nl
Re: A C Macro that reference another macro
« Reply #6 on: November 02, 2021, 03:00:33 pm »
...

All of this code can be generated by a program so you don't have to type it in.
Code: (python) [Select]
for x in range(8):
    print('if(variable & (1<<x)){{OUT_0{x}_ON;}}else{{OUT_0{x}_OFF;}}'.format(x=x))
Try it.

It's weird, but if you want to you can have code write code that generates assembler that compiles to instructions.
This is not one of the situations you want that.

I'd suggest looking up pointers.

For example:
Code: [Select]
typedef struct {
    int number;
    gpio_t GPIO
} io_assignment;

io_assignment outputs[10] = {
/* out 0 */  { 5, GPIOB},
/* out 1 */  { 2, GPIOF},
/* out 2 */  { 1, GPIOD},
...

// usage
outputs[x]->GPIO->SET = 1
Like this?
 

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 151
  • Country: us
Re: A C Macro that reference another macro
« Reply #7 on: November 02, 2021, 03:28:20 pm »
Is there a more elegant solution for this referencing macros?

You can wrap a single `if` from your example into a separate macro layer, thus obtaining something like

Code: [Select]
#include <stdio.h>
#include <stdint.h>

#define OUT_01_ON  printf("1 on\n")
#define OUT_01_OFF printf("1 off\n")

#define OUT_02_ON  printf("2 on\n")
#define OUT_02_OFF printf("2 off\n")

#define OUT_03_ON  printf("3 on\n")
#define OUT_03_OFF printf("3 off\n")

#define TEST_I(variable, I) if (((variable) & (1u << (I) - 1)) != 0) OUT_0##I##_ON; else OUT_0##I##_OFF

int main()
{
  uint8_t v = 0x2;
  TEST_I(v, 1);
  TEST_I(v, 2);
  TEST_I(v, 3);
}

http://coliru.stacked-crooked.com/a/0e546d6fefed3de6

However, once you get to a two-digit indices things might become more complicated: you will either have to abandon the aligned `01`, `02` ,... approach when naming your macros or resort to extra macro-magic to make sure the proper pieces of macro names are generated for short indices. This is all perfectly doable, BTW.

You can also build a "macro-cycle" on top of the above `TEST_I` example, thus effectively achieving exactly what you are asking for. However, it would require a bit of macro-magic framework, similar to Boost.Preprocessor, which will incapsulate all the tedious details. So, this is really a question of whether you want to include that framework into your code. Once you do, you will be able to do quite a lot with macros. But if this is just a one-off situation, then you might be better off using some simpler solution, even if it requires more typing.

---

Of course, a question that immediately pops to mind is why you even have that collection of macros? What are they doing? Could they possibly be folded into a single parameterized macro or function? That would likely open a way to much better solution, possibly not involving macros at all.
« Last Edit: November 02, 2021, 04:03:53 pm by TheCalligrapher »
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14431
  • Country: fr
Re: A C Macro that reference another macro
« Reply #8 on: November 02, 2021, 05:48:53 pm »
For a moment assume that bitmask manipulation is not possible.

Uh, sure. Although I don't think I've ever seen this using a C compiler.
So I'm just wondering - are bitwise operations so inefficient on your particular target that tests would be more efficient (which sounds odd), or are they just not available, meaning you actually use a crippled C compiler - maybe something like for those Padauk MCUs... Just curious.
 

Online DavidAlfa

  • Super Contributor
  • ***
  • Posts: 5890
  • Country: es
Re: A C Macro that reference another macro
« Reply #9 on: November 03, 2021, 08:18:54 am »
For a moment assume that bitmask manipulation is not possible.

if(variable&1){
...

So your example of no bitmask manipulation is actually a bitmask manipulation.
"variable&whatever" is a bitmask.

This uses a macro to reference another macro, might be what you're searching for:
Code: [Select]

#define OUT_OFF     0       // 00: OFF
#define OUT_ON      1       // 01: ON
#define OUT_TOGGLE  2       // 10: TOGGLE

#define OUTS        8       // Number of outputs

#define OUT_0       LATA0   // Declare anything as the outputs
#define OUT_1       LATA1
#define OUT_2       LATB5
#define OUT_3       LATC1
#define OUT_4       LATA7
#define OUT_5       LATB1
#define OUT_6       LATB4
#define OUT_7       LATC5

#define OUT(n)      OUT_##n  // Convert OUT(n) into OUT_N to reference the upper macros


However you can't use a that macro with a dynamic variable!
Ex. You can do this at compile time: OUT(1)
But you can't do OUT(variable).

So you'll need a const struct that defines the port and the pin.
Also, to save space, instead using 3 bits for each output (OFF/ON/TOG modes), use 2 bits and decode them to get 4 states (0-3).
Code: [Select]

#define OUT_OFF     0                   // 00: OFF
#define OUT_ON      1                   // 01: ON
#define OUT_TOGGLE  2                   // 10: TOGGLE
#define OUT_ELSE    3                   // 11: SOMETHING ELSE?

#define OUTS        8                   // Number of outputs

typedef const struct {
    PORT * port;                        // Pointer to GPIO PORT. This can be GPIO* , uint32_t*, uint8_t*...
    uint8_t pin;                        // Pin number
}out_t;

out_t outs[OUTS] = {
  [0] = {                               // PORT 0
      .port = &GPIOA,
      .pin = 0,
  },
  [1] = {                               // PORT 1
      .port = &GPIOA,
      .pin = 1,
  },
  [2] = {                               // PORT 2
      .port = &GPIOB,
      .pin = 4,
  },
  [3] = {                               // PORT 3
      .port = &GPIOC,
      .pin = 6,
  },
  [4] = {                               // PORT 4
      .port = &GPIOC,
      .pin = 1,
  },
 
  // etc ...
};

void update_outs(uint16_t var){        // 2 bits per output, so 16 bit for 8 outputs
    for(uint8_t n=0;n<OUTS;n++){       // 16 bits contents are 77.66.55.44.33.22.11.00
       
        switch( var>>(n*2) & 3 ){      // Extract the 2 bits we need
            case OUT_OFF:
                *outs[n].port &= ~(outs[n].pin);
                break;
               
            case OUT_ON:
                *outs[n].port |= outs[n].pin;
                break;
               
            case OUT_TOGGLE:
                *outs[n].port ^= outs[n].pin;
                break;
               
            case OUT_ELSE:
                break;
               
            default:
                break;
        }
    }
}
« Last Edit: November 03, 2021, 09:58:12 am by DavidAlfa »
Hantek DSO2x1x            Drive        FAQ          DON'T BUY HANTEK! (Aka HALF-MADE)
Stm32 Soldering FW      Forum      Github      Donate
 

Offline Doctorandus_P

  • Super Contributor
  • ***
  • Posts: 3340
  • Country: nl
Re: A C Macro that reference another macro
« Reply #10 on: November 03, 2021, 11:26:04 pm »
It's quite common to have macro's nested in C.

But beware that the preprocessor is not very smart. It is just a text replacement feature, and this may lead to very unexpected results when macro's get nested. For this reason usually all macro's are surrounded by parenthesis
 

Online Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6227
  • Country: fi
    • My home page and email address
Re: A C Macro that reference another macro
« Reply #11 on: November 05, 2021, 12:52:51 pm »
What's with the macro fetishism?

If you use a half-decent C compiler, including SDCC, GCC, clang, Intel C, or even Microsoft C++, and you enable optimization (which you should, always), and you write code similar to
Code: [Select]
/* Pin names */
enum {
    PIN_0 = 0,
    PIN_1,
    /* ... */
    PIN_N,
};

static inline void output_enable(const int pin)
{
    if (pin == PIN_0) {
        /* Code to enable pin 0 */
    } else
    if (pin == PIN_1) {
        /* Code to enable pin 1 */
    } else
    /* Repetition omitted for brevity */
    if (pin == PIN_N) {
        /* Code to enable pin N */
    }
}

static inline void output_disable(const int pin)
{
    if (pin == PIN_0) {
        /* Code to disable pin 0 */
    } else
    if (pin == PIN_1) {
        /* Code to disable pin 1 */
    } else
    /* Repetition omitted for brevity */
    if (pin == PIN_N) {
        /* Code to disable pin N */
    }
}

static inline void output_set(const int pin, const int state)
{
    if (state)
        output_enable(pin);
    else
        output_disable(pin);
}
then output_set(PIN_1, 0) will compile only to whatever you have in /* Code to disable pin 1 */ without any conditionals.  It is nowadays a trivial optimization that even SDCC supports, to detect that the pin number and state are compile-time constants, and inline only the relevant part of the function, omitting any conditional checks.  If the pin is not a compile-time constant but the state is, then either output_enable() or output_disable() gets inlined or called.  Only when neither are compile-time constants, does the actual output() inlined or called.  If the pin numbers are then small consecutive integers, a jump table gets generated (assuming the target architecture supports it), in which case the "cost" of all those if clauses is just one conditional (for the state) and a computed jump: dirt cheap.  (You can get much smaller code size in that case by using suitable tables, though, if you have lots of pins.)

In C, you will want to use either enums or preprocessor macros to "configure" pins; const int MY_PIN = PIN_N; is not a compile-time constant (but both enum { MY_PIN = PIN_N }; and #define MY_PIN PIN_N make MY_PIN a compile-time constant).  In C++, you can also use enums of preprocessor macros, or constexpr int MY_PIN = PIN_N.
 
The following users thanked this post: golden_labels, DiTBho

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14431
  • Country: fr
Re: A C Macro that reference another macro
« Reply #12 on: November 05, 2021, 06:35:00 pm »
These days, I agree that inline functions - and let's not get into the whole inline discussion again, but yes, modern C compilers will inline as much as they can as long as definitions are in the same compilation unit, so the inline qualifier is often not even necessary - are the way to go if the only reason you use macros for is "efficiency".

Now macros have their uses of course, every time they can avoid duplicating code. This is what they were meant for and what they are "good" at. Of course to be used with due care, since they only do text substitution. But I'll certainly favor well-written macros, even when nested several levels, to duplicating code.

But for efficiency - just with the idea of "inlining" code - they do not make much sense anymore.
 

Online Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6227
  • Country: fi
    • My home page and email address
Re: A C Macro that reference another macro
« Reply #13 on: November 06, 2021, 01:00:38 am »
Yup.  It probably makes sense to replace the static inline with a macro, say HELPER_FUNCTION or whatever you consider appropriate, that expands to a set of attributes your compiler prefers for such functions.  For GCC, Clang, and Intel CC, I tend to use __attribute__((unused)) static inline, which really has very little to do with inlining: it just tells the compiler that this function does not need to be used (that is, do not issue a warning if it is not used), is only used in the current compilation unit so there is no need to generate a symbol referring to a callable version of the function, and the compiler is explicitly free to decide for each use whether to inline the function there or just emit a call to a common implementation (and if all instances are inlined, there is no need to have a common implementation at all).

In the earlier days of C, the compilers really didn't do much optimization at all.  Programmers used macros, because that way the compilers generated faster code: they saw each use of the macro as a separate piece of code, and just tried to generate the code to fit into the surrounding situation each time.

Now, the C compilers do a lot of optimization.  They detect use patterns –– for example, so much so that it nowadays doesn't matter to the compiler whether a local variable is marked const or not (which is a promise to the compiler that the code does not attempt to change its value) since they detect if the variable is modified or not.  I still do mark such variables const, but for a completely different reason: it helps us humans read the code, because a promise is a promise, and if const, we don't need to worry that the variable might be modified at some point.  The compilers can tell, but we humans maintaining the code still need the help.

It turns out that the macro trickery tends to be counterproductive with these optimizing C compilers.  It is like unrolling a loop, and then hoping that the compiler can convert the unrolled loop back to a loop if necessary.  (These C compilers can, and sometimes do, unroll loops; but re-rolling an unrolled loop back to a loop is nontrivial and complicated thing to do wrt. the behaviour dictated by the C standard, so that is just not something the compilers currently/normally do.)
 

Offline Doctorandus_P

  • Super Contributor
  • ***
  • Posts: 3340
  • Country: nl
Re: A C Macro that reference another macro
« Reply #14 on: November 06, 2021, 03:02:36 pm »
If you've got 128 of them, then that is a lot of typing.
What do these macro's actually do?
Maybe it's a better solution to write a for loop, and then place your "macro thing" in one (or a few) arrays.


Copy / paste code 128 times is also error prone.
You may want to consider to write a small C program (Or Python or another script language) that generates the C source code in a text file.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14431
  • Country: fr
Re: A C Macro that reference another macro
« Reply #15 on: November 06, 2021, 06:30:20 pm »
In the earlier days of C, the compilers really didn't do much optimization at all.  Programmers used macros, because that way the compilers generated faster code: they saw each use of the macro as a separate piece of code, and just tried to generate the code to fit into the surrounding situation each time.

Oh yeah. Absolutely. Also keep in mind that some people, even to this day, still use pretty old or limited compilers. So in their particular case, using macros may be more efficient too.
Now if you use a GCC version that is not over 20 years old, you shouldn't bother. But some older compilers from vendors can be pretty lame.

Beyond efficiency, macros can still have an edge: they allow some form of meta-programming - making the end code easier to write and to look at, while strictly using functions would not allow some particular syntax or way to manipulate objects and constants. Sometimes a good macro is way nicer to handle than having to go through hoops with functions.
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4026
  • Country: nz
Re: A C Macro that reference another macro
« Reply #16 on: November 06, 2021, 11:11:54 pm »
Beyond efficiency, macros can still have an edge: they allow some form of meta-programming - making the end code easier to write and to look at, while strictly using functions would not allow some particular syntax or way to manipulate objects and constants. Sometimes a good macro is way nicer to handle than having to go through hoops with functions.

Have a look at my use of macros in ...

https://github.com/brucehoult/trv

... and tell me if you think it's disgusting or not :-)

I #define INSTRUCTION to four different expansions in different places, and then #undef it each time.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14431
  • Country: fr
Re: A C Macro that reference another macro
« Reply #17 on: November 07, 2021, 12:05:59 am »
Beyond efficiency, macros can still have an edge: they allow some form of meta-programming - making the end code easier to write and to look at, while strictly using functions would not allow some particular syntax or way to manipulate objects and constants. Sometimes a good macro is way nicer to handle than having to go through hoops with functions.

Have a look at my use of macros in ...

https://github.com/brucehoult/trv

... and tell me if you think it's disgusting or not :-)

Well, I would probably have done it differently. In particular, I usually try to avoid redefining macros. But this is a matter of style. Otherwise I'm OK with it. I also use macros in similar ways. And the '##' operator is handy too.

This shows how macros are useful in a creative way, and here allows to define instructions in just one place, while making it easy to add new instructions.

(Now judging from what some say about the non-trivial use of macros here, I'm pretty sure they will find it awful.)
 

Online Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6227
  • Country: fi
    • My home page and email address
Re: A C Macro that reference another macro
« Reply #18 on: November 07, 2021, 02:34:05 am »
Beyond efficiency, macros can still have an edge: they allow some form of meta-programming - making the end code easier to write and to look at, while strictly using functions would not allow some particular syntax or way to manipulate objects and constants. Sometimes a good macro is way nicer to handle than having to go through hoops with functions.
Yes, definitely.  Even I have shown examples here from generics to basic polymorphism to expanding macros differently based on the number of arguments, all to make it easier for the programmer to implement useful things, without compromising the efficiency of the compiled code.

Macros are an useful tool, but they have their limitations.  It is using macros where something else works better that I referred to as "fetishism".
(I find myself using the "when the only tool you have is a hammer, all problems look like nails" idiom too often, so I tried something else for once.)

Have a look at my use of macros in https://github.com/brucehoult/trv and tell me if you think it's disgusting or not :-)
Not disgusting, just standard way of using the preprocessor for polymorphism, in my opinion.  And very clean implementation, too.

I myself posted a much more "disgusting-looking", but perfectly useful example of this kind of polymorphism, six months ago in the Embedded programming sub-board (Concurrency in a bare metal environment thread).



The most annoying deficiency with the C preprocessor is that no string operations or matching is supported in preprocessor directives.  You can compare and do basic arithmetic with integers, but basically nothing with strings.  To me, it is a good reminder of the limitations of the preprocessor.

One of the most common ways I use macros is default constants that are trivial to override at compile time:
    #ifndef  DEFAULT_VALUE
    #define  DEFAULT_VALUE  42
    #endif
You see, if using GCC/Clang/Intel CC, you just add a cimpile option, say -DDEFAULT_VALUE=99, to override the default.

Another common use case is with preprocessor arithmetic, when I want to treat an undefined macro as a zero, and generate different code based on the macro value:
    #if VALUE-0 == 0
        printf("Value is zero or undefined\n");
    #elif VALUE-0 == 1
        printf("Value is one\n");
    #else
        printf("Value is defined, but neither one nor zero.\n");
    #endif
When used in a preprocessor arithmetic expression, undefined macros are empty.  So, if VALUE is undefined, the preprocessor sees VALUE-0 as -0 which is the same as zero.

This can be a bit confusing, because if you use VALUE in the C code, and it is not defined as a macro, it is then treated as VALUE (i.e., a normal identifier).  It's kinda-sorta the opposite behaviour between the preprocessor and the compiler proper, really.  But useful, nevertheless.
 

Offline DiTBho

  • Super Contributor
  • ***
  • Posts: 3892
  • Country: gb
Re: A C Macro that reference another macro
« Reply #19 on: November 07, 2021, 09:01:57 am »
In the earlier days of C, the compilers really didn't do much optimization at all. 

gcc-v2.95 on BeOS
gcc-v3.0.1 on Luna88k
SierraC for Ticalc
Microchip C for dspic30

everything before ~2004
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline DiTBho

  • Super Contributor
  • ***
  • Posts: 3892
  • Country: gb
Re: A C Macro that reference another macro
« Reply #20 on: November 07, 2021, 09:25:11 am »
Macros are an useful tool, but they have their limitations.  It is using macros where something else works better that I referred to as "fetishism".

like this?

Code: [Select]
/*
 * This macro allows you to obtain
 *       a pointer to a structure
 *       from a pointer to one of its members.
 */
#ifndef struct_from_field
   #define struct_from_field(cstruct, field, pointer) \
    ((cstruct*) ((p_uint8_t) (pointer) - offsetof(cstruct, field)))
#endif

I reworked the whole source to remove this *magic* stuff  :D
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline DiTBho

  • Super Contributor
  • ***
  • Posts: 3892
  • Country: gb
Re: A C Macro that reference another macro
« Reply #21 on: November 07, 2021, 10:13:16 am »
It is using macros where something else works better that I referred to as "fetishism".

Denx' u-boot is the best example of this.

I reworked the code for PowerPC (40xx an PowerQUICC-I / II) and I found it full of macros that should be removed because there are better ways to work the code. I looked at 2008 code, but no nice, even in the 2021 version they insist on keeping that crap with their code and for example you have four macro level to manage PCI

A macro that uses a macro that references a macro that has elements defined in another .h file, and during the process there are a lot of expansions not easy to track down.

And it's not just "powerpc", if you look at the firmware of routers like the TL703, well it's "mips"... and it's terrible for the same reason.
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4026
  • Country: nz
Re: A C Macro that reference another macro
« Reply #22 on: November 07, 2021, 10:13:51 am »
In the earlier days of C, the compilers really didn't do much optimization at all. 

gcc-v2.95 on BeOS
gcc-v3.0.1 on Luna88k
SierraC for Ticalc
Microchip C for dspic30

everything before ~2004

I don't recall gcc 2.95 being all that bad at optimisation. At least it produced correct code, unlike the first couple of years of gcc 3.x.
 

Offline DiTBho

  • Super Contributor
  • ***
  • Posts: 3892
  • Country: gb
Re: A C Macro that reference another macro
« Reply #23 on: November 07, 2021, 10:24:50 am »
I don't recall gcc 2.95 being all that bad at optimisation. At least it produced correct code, unlike the first couple of years of gcc 3.x.

On BeOS-v5.* I remember it was not well optimized on an operating system that aimed to fly on hardware like PentiumIIs (SMP, up to four CPUs supported), so the code here and there was reworked with manual macros to get better performances, and 15-years later that code got reworked again on Haiku for gcc-v9

Funny legacy  ;D
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline golden_labels

  • Super Contributor
  • ***
  • Posts: 1207
  • Country: pl
Re: A C Macro that reference another macro
« Reply #24 on: November 07, 2021, 05:48:45 pm »
It seems that the op lost interest in receiving the answer, if no one noticed. :) Therefore the discussion is somewhat pointless, because we do not know, what they wanted to do.
People imagine AI as T1000. What we got so far is glorified T9.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14431
  • Country: fr
Re: A C Macro that reference another macro
« Reply #25 on: November 07, 2021, 06:52:51 pm »
Well yeah, as often. The discussion drifted off about macros in general, but the OP went away and never answered our questions. But this is usual and nothing special.
 

Offline Kalvin

  • Super Contributor
  • ***
  • Posts: 2145
  • Country: fi
  • Embedded SW/HW.
Re: A C Macro that reference another macro
« Reply #26 on: November 08, 2021, 10:38:31 am »
If you cannot or do not want to use use x-macro wizardry, why don't you just create a simple utility which will generate the required C source code into a file, which you can include into your project. Just add the code generator as a part of your project's makefile, and the tool will regenerate the source code as needed if the utility or its input data file changes.
 

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 8166
  • Country: fi
Re: A C Macro that reference another macro
« Reply #27 on: November 08, 2021, 04:26:40 pm »
Always try with macro wizardry, though.

Code generation is sometimes the unavoidable evil, but using external code generation when the actual language itself supports what is needed directly is just nuts.

In order of preference, try to first make things work without macros, i.e., normal C code. Now if this is impossible, inefficient or results in unreadable code (or copy-pasting, which is evil), use C preprocessor and its features and tricks to achieve what is needed. If this is impossible as well (or unreadable), then as the last resort, go for external code generation.
 

Offline golden_labels

  • Super Contributor
  • ***
  • Posts: 1207
  • Country: pl
Re: A C Macro that reference another macro
« Reply #28 on: November 09, 2021, 01:17:03 am »
One should use the right tool for the job. C preprocessor is very primitive, tricky and using it quickly becomes more trouble than help. Being a language, that is completely separate from C proper, makes it even worse.

If you need simple token replacement or concatenation, it’s perfectly fine. But the moment you move towards decision making and calculations, it turns into a horror. While it is Turing-complete,(1) it is unreadable, requires using an inconvenient input format, can’t be easily debugged and error messages are gibberish.

Using a separate tool is much more convenient and, by all means, better. Even unnatural tools like m4 are considerably better at most tasks you could imagine. Not to mention simply using any popular scripting language that appeared in the past 20 years. Python or Perl are easily obtainable, are open, are free, likely already present on developer’s computer anyway. Something that takes 500 unreadable of lines of C preprocessor, heavily dealing on already pre-generated Boost.Preprocessor, can be cleanly expressed in either of those in just few lines.
____
(1) Subject to resources limitation, which in the case of preprocessor metaprogramming must be manually pre-defined.
« Last Edit: November 09, 2021, 01:20:36 am by golden_labels »
People imagine AI as T1000. What we got so far is glorified T9.
 

Online Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6227
  • Country: fi
    • My home page and email address
Re: A C Macro that reference another macro
« Reply #29 on: November 09, 2021, 07:12:01 am »
Using a separate tool is much more convenient and, by all means, better.
I've used awk to generate precomputed (trigonometric etc. fixed point) tables used on architectures without hardware floating point support, as simple header files.  I do recommend splitting the generated part into a separate file you simply #include in the actual header or source file, instead of using some sort of templates (as certain development environments do), and use an easily recognized file name or extension for it.  Keep It Simple, and consider the human who happens to have to maintain the code a year or two from now: it often is yourself, and you'll be glad then of the consideration.  I am, almost constantly.

I've even used a pre-build C program to generate (and verify perfectness) of a hash table of known keywords/tokens, to speed up configuration file parsing.  Essentially, it uses the given hash function, the list of tokens, and generates the minimum size hash table that has no collisions, brute-forcing it, and emits the result as a nice C header file.  (In this case, it is important to check that the host and target architectures use the same hash algorithm and hash size.  If the hash algorithm works on a byte-by-byte basis, byte order does not matter.)

I've also used objcopy to generate ELF object files directly from binary data, without processing it through the compiler. I usually use a scriptlet that generates a suitable header file describing the object too (including the size, which otherwise would be a link time constant, not a compile time constant).

ELF-based toolchains have a lot of useful tricks you can do to make maintenance easier. Using sections to collect entries in different files into a single contiguous array is one of my favourites: the linker does all the hard work for you, and you only need to make sure that the size of the entries is a multiple of the alignment.  You can even make it an sort-of-list of variable-length entries, if each entry begins with its size.  Very useful for compile-time extensions, menus, and such on embedded environments, as all that data can be put into ROM/Flash, without having to run some "registration" functions at run time: if the facility is linked to the final binary, then the related menu entries are too.  Simples.

There are a lot of useful tools, from macros to data/code generation to pure binary tools, but without additional information on the task at hand, we're just discussing the various options and possible scenarios.

@jealcuna, why did you leave us hanging?  :o
« Last Edit: November 09, 2021, 07:16:43 am by Nominal Animal »
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14431
  • Country: fr
Re: A C Macro that reference another macro
« Reply #30 on: November 09, 2021, 05:28:30 pm »
And yes, as always, it all depends. Sometimes code generators are cool. Sometimes they are just added "noise". Depends on use case.

The C preprocessor is not bad at all IMO. It has the merits of being well known, standard, and doing what we ask it to do. Oh I've tried alternatives in the past too. I too tried using M4. This looked promising at first, but I quickly stepped back. The experience was a lot more painful than expected, with the added issue that having your code maintained by other people would of course be more difficult.

I mostly use code generators - as Nominal mentioned - to generate precomputed tables (including images). Not as meta-programming layer.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf