Author Topic: Help with C language macro stringification  (Read 11444 times)

0 Members and 1 Guest are viewing this topic.

Offline Back2VoltsTopic starter

  • Supporter
  • ****
  • Posts: 495
  • Country: us
Help with C language macro stringification
« on: July 28, 2017, 02:06:54 pm »
I have this macro which works fine

#define LA_TRACE_PORT_DR     (CYREG_PRT0_DR)

but I would like to use a define for the "0", so I am looking for something like the following (with proper syntax)

#define LA_TRACE_PORT_NUM    "0"

#define LA_TRACE_PORT_DR     ("CYREG_PRT#LA_TRACE_PORT_NUM#_DR")     

What is the proper syntax in the last two defines to come up with the equivalent of the first one?     You can imagine that I have tried a few silly variations before I came to post here.     I am not sure it makes a difference, but I am using gcc.

Tony
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 825
Re: Help with C language macro stringification
« Reply #1 on: July 28, 2017, 02:20:32 pm »
#define LA_TRACE_PORT_NUM       0
#define _LA_TRACE_PORT_DR(n)    (CYREG_PRT#n#_DR)
#define LA_TRACE_PORT_DR(n)     _LA_TRACE_PORT_DR(n) 

use-
LA_TRACE_PORT_DR(LA_TRACE_PORT_NUM)

You need the second define so LA_TRACE_PORT_NUM gets processed/reduced.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Help with C language macro stringification
« Reply #2 on: July 28, 2017, 03:34:40 pm »
Code: [Select]
#define LA_TRACE_PORT_NUM 0
#define CONCAT3(a,b,c) a##b##c
#define LA_TRACE_PORT_DR_PROTO(x) (CONCAT3(CYREG_PRT,x,_DR))
#define LA_TRACE_PORT_DR LA_TRACE_PORT_DR_PROTO(LA_TRACE_PORT_NUM)

Usage (should print 15):

Code: [Select]
#define CYREG_PRT0_DR 15
int main(void)
{
  printf("%d\r\n",LA_TRACE_PORT_DR);
}
« Last Edit: July 28, 2017, 03:46:38 pm by NorthGuy »
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: Help with C language macro stringification
« Reply #3 on: July 28, 2017, 05:22:56 pm »
(don't abuse the macro-processor)
 
The following users thanked this post: hans, MarkS, rob.manderson

Offline SimonR

  • Regular Contributor
  • *
  • Posts: 122
  • Country: gb
Re: Help with C language macro stringification
« Reply #4 on: July 28, 2017, 10:18:44 pm »
(don't abuse the macro-processor)

Good point, but its just so tempting
 

Offline Back2VoltsTopic starter

  • Supporter
  • ****
  • Posts: 495
  • Country: us
Re: Help with C language macro stringification
« Reply #5 on: July 29, 2017, 03:42:15 am »
Thank you guys.   I have it working and I promise I will try to avoid macros 

Tony
 

Offline SimonR

  • Regular Contributor
  • *
  • Posts: 122
  • Country: gb
Re: Help with C language macro stringification
« Reply #6 on: July 29, 2017, 10:18:33 am »
Don't avoid them, just be careful how you use them.
 

Offline Kalvin

  • Super Contributor
  • ***
  • Posts: 2145
  • Country: fi
  • Embedded SW/HW.
Re: Help with C language macro stringification
« Reply #7 on: July 29, 2017, 11:13:58 am »
You may want to familiarize yourself to X Macros: https://en.wikipedia.org/wiki/X_Macro Check also the article references. X Macros are handy things to know. However, do not overuse them :)
 
The following users thanked this post: helius

Offline Hypernova

  • Supporter
  • ****
  • Posts: 655
  • Country: tw
Re: Help with C language macro stringification
« Reply #8 on: July 29, 2017, 12:39:00 pm »
(don't abuse the macro-processor)

What good is power if you can't abuse it?  >:D
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: Help with C language macro stringification
« Reply #9 on: July 29, 2017, 01:06:00 pm »
What good is power if you can't abuse it?  >:D
[/quote]

( eh, when are you in a rush, and ...
you find that the macro processor has just done a mess
May God save the Queen)
 

Offline Hypernova

  • Supporter
  • ****
  • Posts: 655
  • Country: tw
Re: Help with C language macro stringification
« Reply #10 on: July 29, 2017, 01:22:52 pm »
What good is power if you can't abuse it?  >:D

( eh, when are you in a rush, and ...
you find that the macro processor has just done a mess
May God save the Queen)

Hence you are supposed to dish out macro gymnastics in small doses at a time.

The most complex macro I've done generated inline assembly statements from a standard string declaration. TI's C2000 series have 16bit chars so every string takes up double the size. For reasons  unknown the statements to define "packed" strings are available only in assembly.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Help with C language macro stringification
« Reply #11 on: July 29, 2017, 02:24:26 pm »
( eh, when are you in a rush, and ...
you find that the macro processor has just done a mess
May God save the Queen)

Macros don't make mess. People make mess.

People who don't like macros usually make more mess :)
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: Help with C language macro stringification
« Reply #12 on: July 29, 2017, 03:40:05 pm »
( eh, when are you in a rush, and ...
you find that the macro processor has just done a mess
May God save the Queen)

Macros don't make mess. People make mess.

People who don't like macros usually make more mess :)


People like the person with whom one works, especially in a profession or business?
Sure, and it's a basket of plus all the time :D
 

Offline MarkS

  • Supporter
  • ****
  • Posts: 825
  • Country: us
Re: Help with C language macro stringification
« Reply #13 on: July 29, 2017, 10:10:00 pm »
I have it working and I promise I will try to avoid macros 

Use macros to define constants. The macro processor is rather powerful and you can do a lot with it, but the more you do, the harder it gets to debug the code. If you need the macro to operate as a function, write a function.
 

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Re: Help with C language macro stringification
« Reply #14 on: July 29, 2017, 11:45:31 pm »
Use macros to define constants.
Please don't.

You shouldn't use macros for anything that you can do in the language itself. It's much better to define numeric constants as enums. E.g.,

Code: [Select]
enum {
  FOO = 0x00000001u
};

is preferable to:
Code: [Select]
#define FOO 0x0000001u
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: Help with C language macro stringification
« Reply #15 on: July 30, 2017, 08:55:11 am »
Use macros to define constants.
Please don't.

You shouldn't use macros for anything that you can do in the language itself. It's much better to define numeric constants as enums. E.g.,

Code: [Select]
enum {
  FOO = 0x00000001u
};

is preferable to:
Code: [Select]
#define FOO 0x0000001u

Ew! declaring things as unnamed, unused enums so you can use them as constants? That seems so dirty!

At least it gets around the errors when you use a const to size an array:
Code: [Select]
$ cat c.c
const int sector_size = 512;

unsigned char sector[sector_size];

int main(int argc, char *argv[]) {
  return 0;
}
$ gcc -o c c.c
c.c:3:15: error: variably modified ‘sector’ at file scope
 unsigned char sector[sector_size];
               ^

But this works:

Code: [Select]
enum { sector_size = 512 };

unsigned char sector[sector_size];

int main(int argc, char *argv[]) {
  return 0;
}


Me? I'ld take "#define SECTOR_SIZE (512)" any day.... but that you never know, it might grow on me.

I might even make a macro for it!
« Last Edit: July 30, 2017, 08:58:06 am by hamster_nz »
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Help with C language macro stringification
« Reply #16 on: July 30, 2017, 01:54:19 pm »
You shouldn't use macros for anything that you can do in the language itself.

The pre-processor is the part of the C language.
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: Help with C language macro stringification
« Reply #17 on: July 30, 2017, 02:10:48 pm »
The pre-processor is the part of the C language.

Well, physically it's an external tool, since everything that begins with "#" (e.g. #define) is not handled by CC, it's pre-processed by CPP.

C source & H header -> macro expansion (by CPP) -> object file (by CC).


 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Help with C language macro stringification
« Reply #18 on: July 30, 2017, 02:39:15 pm »
The pre-processor is the part of the C language.

Well, physically it's an external tool, since everything that begins with "#" (e.g. #define) is not handled by CC, it's pre-processed by CPP.

C source & H header -> macro expansion (by CPP) -> object file (by CC).

The C language is not concerned with the implementations. It is only concerned with the results:

"The semantic descriptions in this International Standard describe the behavior of an abstract machine ..." C99 5.1.2.3.1
 
The following users thanked this post: newbrain

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Re: Help with C language macro stringification
« Reply #19 on: July 30, 2017, 03:36:09 pm »
Me? I'ld take "#define SECTOR_SIZE (512)" any day.... but that you never know, it might grow on me.

Well yeah, that works. One practical reason against macro constants is that they're unknown to your debugger, since they get stripped away before the compiler. Macros are also sloppy when it comes to strong typing.

Frequently, I'll use enums in an API when I want to make sure that an argument to a function/method has a limited range of values and enforce that at compile time. ints are, well, integers, and force you to check stuff at runtime (if at all).

Truth be told, I spend most of my time in C++ and depend heavily on compile-time type checking to keep me out of the weeds. Things like strongly type enums and 'const' (did I just hear a gasp from the back row?) flush a lot of problems out before I fire up the J-Link.

And my static constexpr function can beat up your #define expansion any day of the week. ;-)

The pre-processor is the part of the C language.

Is it really? The C standard is pretty specific about how expressions are evaluated. E.g., what something like "a+b" means when the types of the identifiers are specified. But when you don't know those types, the standard won't have much to say.

I've got a special rule in most of my makefiles that produces the preprocessed output only (i.e., no object code) specifically for tracking down goofy things that happen with macros:

Code: [Select]
$(BUILD)/%.E : %.c | $(BUILD)
@echo Compiling $(subst $(ABS_ROOT),,$(<))
@$(CC) $(CFLAGS) -E -c $< -o $(@)

I like the preprocessor for #include, #pragma once and X-macros, but constants and inline functions are better handled (IMO) by constants in the language itself and inline functions.

...

I'll confess that I've been abusing the preprocessor on a recent project though. Some of the code is automatically generated (CubeMX) and the generated main() conflicts with mine, causing the linker to complain.

But the preprocessor can get around this by changing function names from the outside. Another gnu makefile snippet:

Code: [Select]
$(OBJ)/$(BOARD)/cubemx/Src/main.o : CFLAGS += -Dmain=cubemx_generated_main

That defines "main" to be a macro that evaluates to some other name, but just for the compilation of that one specific file. It requires a target-specific variable definition in the Makefile, which I'm sure crosses a line.  :o But it's a lot easier than having to sed the output.
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: Help with C language macro stringification
« Reply #20 on: July 30, 2017, 04:28:07 pm »
The C language is not concerned with the implementations. It is only concerned with the results:

Precisely another defect of the C language: are you really sure two implementations produce exactly the same results? In several circumstances I have experimented different behaviors with different compilers and pre-processors.

But the point was: the macro processor simply replaces patterns without being aware of the size, type and signed.

Too bad.
 

Offline Nusa

  • Super Contributor
  • ***
  • Posts: 2416
  • Country: us
Re: Help with C language macro stringification
« Reply #21 on: July 30, 2017, 05:19:52 pm »
The C language is not concerned with the implementations. It is only concerned with the results:

Precisely another defect of the C language: are you really sure two implementations produce exactly the same results? In several circumstances I have experimented different behaviors with different compilers and pre-processors.

But the point was: the macro processor simply replaces patterns without being aware of the size, type and signed.

Too bad.

Indeed. Over the years I've lost count of the number of annoying portability errors I've fixed simply by moving same-line // comments to their own line. Mostly in other peoples code. I learned not to same-line comment defines a long time ago, even if you can get away with it 99% of the time.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Help with C language macro stringification
« Reply #22 on: July 30, 2017, 06:00:32 pm »
Precisely another defect of the C language: are you really sure two implementations produce exactly the same results? In several circumstances I have experimented different behaviors with different compilers and pre-processors.

Of course, there could be bugs in implementations. It's true for every language or tool. How's that a defect of a language?

From my experience, bugs are relatively rare in C. If you stick to the standard and understand what you're doing, it is very likely to be portable.

But the point was: the macro processor simply replaces patterns without being aware of the size, type and signed.

That's right. It writes your program for you exactly as you said. Why should it worry about the types? Like text editor. It doesn't worry about types. Does this bother you?
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Help with C language macro stringification
« Reply #23 on: July 30, 2017, 06:12:05 pm »
The pre-processor is the part of the C language.

Is it really? The C standard is pretty specific about how expressions are evaluated. E.g., what something like "a+b" means when the types of the identifiers are specified. But when you don't know those types, the standard won't have much to say.

The C standard is also very specific about how the pre-processor work. In fact, it is more specific about the pre-processor than it is about typed expressions.

 

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Re: Help with C language macro stringification
« Reply #24 on: July 30, 2017, 07:58:19 pm »
The C standard is also very specific about how the pre-processor work. In fact, it is more specific about the pre-processor than it is about typed expressions.

OK, so we can agree the preprocessor is both well defined and standardized. That doesn't mean it's a good idea to use macro substitutions for constants, although one certainly can.

Let's flip it around... What advantages does a macro offer over a proper C constant?
« Last Edit: July 30, 2017, 08:09:07 pm by andyturk »
 

Offline MarkS

  • Supporter
  • ****
  • Posts: 825
  • Country: us
Re: Help with C language macro stringification
« Reply #25 on: July 30, 2017, 08:43:44 pm »
Let's flip it around... What advantages does a macro offer over a proper C constant?

A macro defines a constant, i.e., the value doesn't change. To say this isn't a proper C constant is disingenuous.

These are both functionally identical, at least to the compiler, although potentially producing slightly different (and irrelevant) machine code:

Code: [Select]
#define some_constant 100
.
.
.
int array[some_constant];

Code: [Select]
enum{
some_constant = 100
};
.
.
.
int array[some_constant];

The difference is that one is evaluated during the preprocessor stage and one at compile time. Enums are more powerful yes, but that doesn't mean that the macros have no value. Ultimately, it comes down to familiarity. I started programming in C just shortly after enums came into the C vernacular, so #define is more familiar to me for this purpose. At the time all code examples used #define for constants; It's how I learned. One is different than the other, not one is good and the other bad. To be clear, most modern day compilers would produce exactly the same machine code from the above examples.

Now, when you get into C++, the preprocessor is evil and to be avoided lest your computer go up in flames. In C++, you use "const".
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: Help with C language macro stringification
« Reply #26 on: July 30, 2017, 09:00:50 pm »
A macro defines a constant

it doesn't define anything
it replaces occurrences in the text.
It does the same job as SED.
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: Help with C language macro stringification
« Reply #27 on: July 30, 2017, 09:02:31 pm »
we can agree the preprocessor is both well defined and standardized

it's not.
e.g. sierra cpp vs gnu cpp
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: Help with C language macro stringification
« Reply #28 on: July 30, 2017, 09:24:44 pm »
Quote
The C standard is pretty specific about how expressions are evaluated

False. It's implementation dependent.

e.g. if you put functions inside an expression, the order in which functions are evaluated is known that might be different depending on the used C compiler.

The same happens with the macro processor for complex macros, typically when you try to define a function with a macro.

The C language is affected by "nasal demons". Undefined behaviors where the semantics of certain operations is described as undefined on the executing computer code whose behavior is not prescribed by the language specification to which the code adheres. This happens when the translator of the source code makes certain assumptions, but these assumptions are not satisfied during execution.

Since all the assumptions made by cpp come from a simple "text replacement", there is no information between these two modules, and, as consequence, nasal demons can take place without a single line of warning.

When the compiler encounters [a given undefined construct] it is legal for it to make demons fly out of your nose

Be warned about that.
 

Offline MarkS

  • Supporter
  • ****
  • Posts: 825
  • Country: us
Re: Help with C language macro stringification
« Reply #29 on: July 30, 2017, 09:34:32 pm »
A macro defines a constant

it doesn't define anything
it replaces occurrences in the text.
It does the same job as SED.

Don't be pedantic.
 

Offline MarkS

  • Supporter
  • ****
  • Posts: 825
  • Country: us
Re: Help with C language macro stringification
« Reply #30 on: July 30, 2017, 09:35:34 pm »
we can agree the preprocessor is both well defined and standardized

it's not.
e.g. sierra cpp vs gnu cpp

We're not talking about C++.
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: Help with C language macro stringification
« Reply #31 on: July 30, 2017, 09:41:58 pm »
Don't be pedantic.

I assume you don't know what "define" implies!

type? size? kind? ... they are not optional since they can cause problems.

None of them are defined by #define. It's a good practice to force the size of a constant, but it's not a must. Thus people do what they want do to, and the source code is usually I mess.

 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Help with C language macro stringification
« Reply #32 on: July 30, 2017, 09:45:57 pm »
The C standard is also very specific about how the pre-processor work. In fact, it is more specific about the pre-processor than it is about typed expressions.

OK, so we can agree the preprocessor is both well defined and standardized. That doesn't mean it's a good idea to use macro substitutions for constants, although one certainly can.

Let's flip it around... What advantages does a macro offer over a proper C constant?

Pre-processor lets you do lots of different things. What you mean by "defining constants" is just a very small part of it. You can use macros as you see fit. It is nothing wrong with this. Same with "enum" - you can use it as you see fit and this is nothing wrong with this neither.

The purpose of macros and enums are different. Sometimes there could be a situation where you can use a macro or enum. Well, use either. It doesn't matter. Your programs won't get better if you always use enums in these situations. Nor are they going to get better if you decide not to use enums. These choices have nothing to do with the quality of the software you write. But, if you concentrate on algorithms and other tangible things instead of worrying about choices between macros and enums, your software will get better.

 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: Help with C language macro stringification
« Reply #33 on: July 30, 2017, 10:00:42 pm »
We're not talking about C++.

SierraC is not C++

I compared a C compiler with another C compiler.

If you prefer you can see the difference between
- intelC
- Gcc/C
- Watcom C
- SierraC
- ...

Now don't want to make a point of distinguishing between
- implementation-defined
- unspecified
- undefined behavior
probably, in your head, they sound irrelevant like something that will never happen. Hope so, otherwise looking at several C compilers for business job to do, you might have some exciting news about your assumptions.
 

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Re: Help with C language macro stringification
« Reply #34 on: July 30, 2017, 10:24:11 pm »
Sometimes there could be a situation where you can use a macro or enum. Well, use either. It doesn't matter. Your programs won't get better if you always use enums in these situations. Nor are they going to get better if you decide not to use enums. These choices have nothing to do with the quality of the software you write. But, if you concentrate on algorithms and other tangible things instead of worrying about choices between macros and enums, your software will get better.

Actually, understanding how to use the language well is part of what makes code "better". Using the preprocessor macros for constants was OK 40 years ago, when the compiler didn't support constants. But there's no real utility in doing that today, and lots of drawbacks. Google basically outlaws preprocessor macros for their 100M+ line C++ codebase.

EDIT: More from Google on macros.
« Last Edit: July 30, 2017, 10:31:05 pm by andyturk »
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Help with C language macro stringification
« Reply #35 on: July 30, 2017, 11:05:58 pm »
Actually, understanding how to use the language well is part of what makes code "better".

Of course, you need to understand the language you use. But it is actually a very small and not important part of the programming process. If you come up with a good solution, you can write it in C, or in Pascal, or Whatever, and you will get very similar result. Even though C has macros (and I would probably use them in most cases), but Pascal doesn't (and I would get by without them).

Some languages, such as C# or java involve performance penalties at the outset. IMHO, it is silly to use them because you could just do the same in C with approximately the same effort, and results would obviously be better. But many people seem to be delusional about that - they think that using certain languages instead of others give them some sort of magical advantage.

Google. They certainly like imposing their rules on the world. Doesn't mean their rules are any good.

 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: Help with C language macro stringification
« Reply #36 on: July 31, 2017, 12:08:03 am »
Google basically outlaws preprocessor macros for their 100M+ line C++ codebase.

EDIT: More from Google on macros.

If only the could outlaw paying their fair share of taxes as easily....

One benefits of #define is that it provides a path to share information between the build environment and the resulting code - usually the -D command line switch.



Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline John Coloccia

  • Super Contributor
  • ***
  • Posts: 1212
  • Country: us
Re: Help with C language macro stringification
« Reply #37 on: July 31, 2017, 01:01:21 am »
Google is talking C++ code, not C, and there are C++ ways to do things that don't require the use of a traditional macro.

const int i = 5;
int array;

is just one example that works in C++ and doesn't work in C for normal arrays.
 

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Re: Help with C language macro stringification
« Reply #38 on: July 31, 2017, 02:10:16 am »
One benefits of #define is that it provides a path to share information between the build environment and the resulting code - usually the -D command line switch.

Yup. Very handy. :-+

Google is talking C++ code, not C, and there are C++ ways to do things that don't require the use of a traditional macro.

const int i = 5;
int array;

is just one example that works in C++ and doesn't work in C for normal arrays.

You sure?

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

const int i = 10;
int array[i];

int main(int argc, char *argv[]) {
  printf("sizeof(array) = %lu\n", sizeof(array));
}

When I compile this on a mac using the C89 standard, it works just fine:

Code: [Select]
$ cc -std=c89 foo.c
$ ./a.out
sizeof(array) = 40
$ cc --version
Apple LLVM version 8.1.0 (clang-802.0.42)
Target: x86_64-apple-darwin16.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
$

Heck, it even allows a const in in a case with -std=c89:

Code: [Select]
void foo(int arg) {
  switch (arg) {
  case i : break;
  default : break;
  }
}

So, if the C standard of 28 years ago allows for these kinds of constants, is there still a reason to be using #define for this stuff in 2017?
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: Help with C language macro stringification
« Reply #39 on: July 31, 2017, 02:31:36 am »
One benefits of #define is that it provides a path to share information between the build environment and the resulting code - usually the -D command line switch.

Yup. Very handy. :-+

Google is talking C++ code, not C, and there are C++ ways to do things that don't require the use of a traditional macro.

const int i = 5;
int array;

is just one example that works in C++ and doesn't work in C for normal arrays.

You sure?

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

const int i = 10;
int array[i];

int main(int argc, char *argv[]) {
  printf("sizeof(array) = %lu\n", sizeof(array));
}

When I compile this on a mac using the C89 standard, it works just fine:

Code: [Select]
$ cc -std=c89 foo.c
$ ./a.out
sizeof(array) = 40
$ cc --version
Apple LLVM version 8.1.0 (clang-802.0.42)
Target: x86_64-apple-darwin16.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
$

Heck, it even allows a const in in a case with -std=c89:

Code: [Select]
void foo(int arg) {
  switch (arg) {
  case i : break;
  default : break;
  }
}

So, if the C standard of 28 years ago allows for these kinds of constants, is there still a reason to be using #define for this stuff in 2017?

Not on GCC 4.8.4:

Code: [Select]
$ gcc -o c c.c -std=c89
c.c:4:5: error: variably modified ‘array’ at file scope
 int array[i];
     ^

Didn't work with standards of c89, c99, c11, gnu99, gnu11...
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Help with C language macro stringification
« Reply #40 on: July 31, 2017, 03:57:28 am »
When I compile this on a mac using the C89 standard, it works just fine:

It is illegal according to C99 standard. It may work in your compiler. But if you use it with other C compiler it may fail. Therefore, if you want portability, you shouldn't use it. If portability is not needed then it is Ok, of course.

BTW, While your code is illegal, this would be perfectly legal in function scope:

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

const int z = 5;

int main(void)
{
  int x[z];
  int k = sizeof(x);
  printf("sizeof = %d\r\n",k);
}

But this actually creates a variable-size array instead of a constant one. What difference does it make? A very noticeable one. Here's the result (GCC 4.5.0 on Linux):

Code: [Select]
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %ecx
subl $16, %esp
movl %esp, %eax
movl %eax, %ebx
movl z, %eax
decl %eax
movl %eax, -12(%ebp)
movl z, %eax
sall $2, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
subl %eax, %esp
movl %esp, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -16(%ebp)
movl z, %eax
sall $2, %eax
movl %eax, -20(%ebp)
movl $.LC0, %eax
subl $8, %esp
pushl -20(%ebp)
pushl %eax
call printf
addl $16, %esp
movl %ebx, %esp
leal -8(%ebp), %esp
addl $0, %esp
popl %ecx
popl %ebx
popl %ebp
leal -4(%ecx), %esp
ret

Now, let's try the same with a macro:

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

#define z 5

int main(void)
{
  int x[z];
  int k = sizeof(x);
  printf("sizeof = %d\r\n",k);
}

Here's the result:

Code: [Select]
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $36, %esp
movl $20, -12(%ebp)
movl $.LC0, %eax
subl $8, %esp
pushl -12(%ebp)
pushl %eax
call printf
addl $16, %esp
movl -4(%ebp), %ecx
leave
leal -4(%ecx), %esp
ret

Just to clarify, here's the extra bloat the "constant" version produces compared to the "macro" version of the code:

Code: [Select]
movl %esp, %eax
movl %eax, %ebx
movl z, %eax
decl %eax
movl %eax, -12(%ebp)
movl z, %eax
sall $2, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
subl %eax, %esp
movl %esp, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -16(%ebp)
movl z, %eax
sall $2, %eax
movl %eax, -20(%ebp)

You didn't expect such a result, did you?

 
The following users thanked this post: newbrain

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Re: Help with C language macro stringification
« Reply #41 on: July 31, 2017, 04:45:30 am »
Didn't work with standards of c89, c99, c11, gnu99, gnu11...

Hmm. Maybe Clang/LLVM is being too flexible here.

But this actually creates a variable-size array instead of a constant one. What difference does it make? A very noticeable one.

Yuck. Definitely don't want a variable-sized array.  :--

Quote
You didn't expect such a result, did you?

To be honest, I was surprised the example compiled with -std=c89, but didn't investigate further. My mistake. Most of my work these days is with GCC 5.x and 6.x for Cortex-M, so what works (or doesn't) with other compilers and/or architectures isn't something I spend much time thinking about. I'm much more up-to-speed on the differences between std=c++11 and std=c++14 though.  8)

So it seems that if you're dealing with ancient compilers or ancient standards (e.g., C89), then yes, by all means keep using #define for constants. But the case for continuing that style with more modern compilers seems less clear.
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: Help with C language macro stringification
« Reply #42 on: July 31, 2017, 05:11:03 am »
BTW, While your code is illegal, this would be perfectly legal in function scope:

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

const int z = 5;

int main(void)
{
  int x[z];
  int k = sizeof(x);
  printf("sizeof = %d\r\n",k);
}

Cool! So the stack is the new heap  ;D Mentally I'm still stuck with a fixed size stack frame.

How do you trap memory exhaustion with that one? Because you will be far more likely to blow the stack than if you are holding fixed length frames.

And does that mean that all nested variable declarations in a function become computed rather than 'base_pointer+fixed_offset_in_stack_frame' addressing? For example:

Code: [Select]
int func(int a) {
  int array[a];
  /* do stuff with array */
  if(....) {
    int b;
    /* Do stuff with b, which will not be at a fixed offset in the stack frame but depends on the size of 'array' */
  }
}

Oh, and how does it handle alignment - does it round up the allocated size to ensure that things won't cross the native word boundaries?

So many questions, so little sense of what the machine will actually be doing...

But I can see how it prevent programmers from leaking memory by malloc()ing but not free()ing buffers.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Help with C language macro stringification
« Reply #43 on: July 31, 2017, 03:29:21 pm »
So it seems that if you're dealing with ancient compilers or ancient standards (e.g., C89), then yes, by all means keep using #define for constants. But the case for continuing that style with more modern compilers seems less clear.

I see, magic new compilers and all that. We've heard it well before the ancient compilers which I use today ever appeared.
 

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Re: Help with C language macro stringification
« Reply #44 on: July 31, 2017, 03:50:18 pm »
I see, magic new compilers and all that. We've heard it well before the ancient compilers which I use today ever appeared.

 I'm curious, which "ancient compilers" are you using?
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Help with C language macro stringification
« Reply #45 on: July 31, 2017, 03:53:24 pm »
And does that mean that all nested variable declarations in a function become computed rather than 'base_pointer+fixed_offset_in_stack_frame' addressing? For example:

If there's only one variable array, the compiler still can use 'base_pointer+fixed_offset_in_stack_frame'. It just has to allocate the array at the end of all other variables. Although it depends on the architecture - stack may grow up or down, there may be parameters in the stack etc.

If there are very many of these, it gets very hard for the compiler. It has to allocate all these arrays and not to lose the track where they are. Since the stack pointer is moving during the allocation process, it's not that easy to find storage for all the corresponding. Probably the best idea is to maintain a linked list of allocated arrays in the stack, and then when everything is done you can walk through the list, extract the pointers and store them at fixed locations relative the stack frame base. Such a PITA to implement for the compiler, and then nobody uses it anyway :) I don't know how GCC does multiple arrays, but you can compile and look.

But actually it is more efficient than the heap. This may be especially useful with small devices which do not have a heap. Also stack will not fragment. Of course, it makes it difficult to analyze stack behaviour. Not a problem on PC, but may be a problem with a small embedded.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Help with C language macro stringification
« Reply #46 on: July 31, 2017, 04:19:43 pm »
I'm curious, which "ancient compilers" are you using?

You wouldn't believe me if I told you :)

The assembly I posted was produced by:

Code: [Select]
[~]# gcc --version
gcc (GCC) 4.5.0
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

 

Offline John Coloccia

  • Super Contributor
  • ***
  • Posts: 1212
  • Country: us
Re: Help with C language macro stringification
« Reply #47 on: July 31, 2017, 10:34:23 pm »
BTW, thanks to everyone that picked up on my typo and knew what I was trying to say without making a big deal about it!

FWIW, the coding standards I just finished writing says something to the effect of, "Avoid macros where possible...prefer to use const." I wish coding standards could simply say, "Please, just make your code look like the code around it, and otherwise just use common sense and don't make a mess," but that never seems to work.
 

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Re: Help with C language macro stringification
« Reply #48 on: July 31, 2017, 11:41:25 pm »
BTW, thanks to everyone that picked up on my typo and knew what I was trying to say without making a big deal about it!

FWIW, the coding standards I just finished writing says something to the effect of, "Avoid macros where possible...prefer to use const." I wish coding standards could simply say, "Please, just make your code look like the code around it, and otherwise just use common sense and don't make a mess," but that never seems to work.

Clang-format goes a long way towards eliminating time spent fussing over code formatting. The projects I work on use it as the de facto description of what code is supposed to look like. I.e., we discuss/argue over how to configure the formatter, and then the rule becomes: "Clang-format everything before you check it in. Period." It integrates with many stand-alone editors these days, and some folks even set it up as a pre commit hook.

https://clang.llvm.org/docs/ClangFormat.html

When someone hands me a bunch of ugly OEM code that wraps at the 200th column (or some such), I just clang-format the whole thing in emacs. Takes a couple of seconds.
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Help with C language macro stringification
« Reply #49 on: August 01, 2017, 02:38:08 am »
"Please, just make your code look like the code around it, and otherwise just use common sense and don't make a mess," but that never seems to work.

Perhaps you hire wrong people.

 

Online Fredderic

  • Regular Contributor
  • *
  • Posts: 68
  • Country: au
Re: Help with C language macro stringification
« Reply #50 on: August 01, 2017, 05:43:26 am »
If there are very many of these, it gets very hard for the compiler. It has to allocate all these arrays and not to lose the track where they are. Since the stack pointer is moving during the allocation process, it's not that easy to find storage for all the corresponding. Probably the best idea is to maintain a linked list of allocated arrays in the stack, and then when everything is done you can walk through the list, extract the pointers and store them at fixed locations relative the stack frame base. Such a PITA to implement for the compiler, and then nobody uses it anyway :) I don't know how GCC does multiple arrays, but you can compile and look.

Actually, pretty sure the stack pointer is pretty much irrelevant during execution of a function.  It's the base pointer that anchors the functions arguments and locals.  The compiler simply allocates ALL variables a slot on the stack at compile time, regardless of where in the function they occur, at what scope depth, etc., which includes stack-allocated arrays — they get a pointer variable up-front like any other array.  The compiler then basically does the equivalent of inlining a malloca call, to allocate the actual array.  Since the base pointer anchors the function arguments and locals, the stack pointer can do what it likes, and you simply subtract as much space as you need off the stack pointer, and use that as the base of your array.

Seriously, in the middle of a function, pick a small random number, subtract it from the stack pointer, and everything keeps working just fine.  You can do it as often as you like (as long as you don't run out of stack space, of course), and all you've done is wasted some space on your stack.

It works because the compiler does essentially the exact same thing itself to allocate a functions own local variables.  The caller basically pushes whatever it needs to save, followed by the arguments to the function it's calling, that function then pushes the current base pointer, and sets it to the current stack pointer, before subtracting the space it wants to allocate for it's own local variables.  Done.  On the way back out, it can simply ditch the current stack pointer, setting it back to the base pointer, load the previous base pointer back off the stack, and return back to the caller, which simply adds the space taken by those arguments back onto the stack pointer (rather than fiddling around with popping them off again).  No need to keep track of anything much, other than the functions own arguments and locals.
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Re: Help with C language macro stringification
« Reply #51 on: August 01, 2017, 07:27:26 am »
Actually, pretty sure the stack pointer is pretty much irrelevant during execution of a function.

On modern processors it is now mostly a convention - on older ones the hardware had special instructions that maintained the base pointer for you.

Hence the following option in GCC:
Quote
-fomit-frame-pointer
        Don't keep the frame pointer in a register for functions that don't
need one. This avoids the instructions to save, set up and restore frame
pointers; it also makes an extra register available in many functions. It
also makes debugging impossible on some machines.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline John Coloccia

  • Super Contributor
  • ***
  • Posts: 1212
  • Country: us
Re: Help with C language macro stringification
« Reply #52 on: August 01, 2017, 07:36:14 am »
"Please, just make your code look like the code around it, and otherwise just use common sense and don't make a mess," but that never seems to work.

Perhaps you hire wrong people.

Oh, it doesn't matter who you hire. I could hire 10 copies of me and I'd still need to have written standards to keep it all straight. There are too many correct ways of doing something, but only one of them is right...the one in the standard. :)
 

Offline legacy

  • Super Contributor
  • ***
  • !
  • Posts: 4415
  • Country: ch
Re: Help with C language macro stringification
« Reply #53 on: August 01, 2017, 09:27:42 am »
On modern processors it is now mostly a convention - on older ones the hardware had special instructions that maintained the base pointer for you.

I am thinking about the RISC way to pass parameters to a function to be called: they can use registers instead of pushing thing on the stack.

But! Since registers are limited, it only works if parameters are compliant to the model (which is based on statistics, e.g. if usually functions have no more than 4 parameters, then 4 registers are reserved), otherwise we are back to the traditional model. In this case, on MIPS, I see a lot of compilers want to save the stack pointer before pushing on the stack, and then they simple resume comping back the frame pointer into the stack pointer

save sp into fp
reserve space for the return ansers (if any)
push parameters
call the function
save fp into sp
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 3146
  • Country: ca
Re: Help with C language macro stringification
« Reply #54 on: August 01, 2017, 01:36:44 pm »
Actually, pretty sure the stack pointer is pretty much irrelevant during execution of a function.  It's the base pointer that anchors the functions arguments and locals.  The compiler simply allocates ALL variables a slot on the stack at compile time, regardless of where in the function they occur, at what scope depth, etc., which includes stack-allocated arrays — they get a pointer variable up-front like any other array.  The compiler then basically does the equivalent of inlining a malloca call, to allocate the actual array.  Since the base pointer anchors the function arguments and locals, the stack pointer can do what it likes, and you simply subtract as much space as you need off the stack pointer, and use that as the base of your array.

Yes, that is an easy mechanism if the compiler maintains a frame pointer which is separate from the stack pointer. I guess even if the compiler doesn't use frame pointers, it can make an exception for the functions with variable-size arrays.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf