2

I want to dynamically create pre-proccessor literal strings where part of the string is created by some arithmetic, for example: math(x) x - 0x1234. The generated definitions would be made by the macro:get_tex_uniform_name(unit), and the results would be the same values as the following numerically ordered definitions:

// texture uniform naming
#define TEX_UNIFORM_BASE_NAME       "tex"
#define TEX_UNIFORM_0               TEX_UNIFORM_BASE_NAME"0"  // "tex0" and so on
#define TEX_UNIFORM_1               TEX_UNIFORM_BASE_NAME"1"
#define TEX_UNIFORM_2               TEX_UNIFORM_BASE_NAME"2"
#define TEX_UNIFORM_3               TEX_UNIFORM_BASE_NAME"3"

I have tried generating the string from scratch with STRINGIFY (#):

#define get_tex_unit_num(unit) unit - GL_TEXTURE0
// create string literal from whatever is put in
#define STRINGIFY(x) #x
#define LITERAL_STRINGIFY(x) STRINGIFY(x)
#define get_tex_uniform_name(unit) TEX_UNIFORM_BASE_NAME LITERAL_STRINGIFY(get_tex_unit_num(unit))

// issue: result is "texunit - 0x84C0", 0x84C0 being GL_TEXTURE0

I have tried token pasting to work with existing definitions:

#define get_tex_unit_num(unit) unit - GL_TEXTURE0
#define get_tex_uniform_name(unit) TEX_UNIFORM_ ## get_tex_unit_num(unit)

// error: TEX_UNIFORM_get_tex_unit_num is undefined

And have been trying to get some sort of bit masking to work:

#define TEX_UNIFORM_BASE_NAME       "tex "

#define get_tex_unit_num(unit) unit - GL_TEXTURE0
#define get_tex_uniform_name(unit) TEX_UNIFORM_BASE_NAME & (0xffffff00 + (char)get_tex_unit_num(unit))

// error: expression must have integral or unscoped enum type

I know that this could be done with functions or by just using the concatenated literal strings as defined in the first example. I am not necessarily looking for a reason why my examples don't work. I am looking for a way to get these strings dynamically, and am having trouble using arithmetic inside macros to create a string literal.

ichster
  • 23
  • 5
  • I feel like it'll take an entire answer to explain exactly how you need to clarify your question, before it can be answered. A *macro* cannot reduce an *expression* (aka, `0xFFFFFF00-get_tex_unit_num(unit))`) to a number. *The preprocessor* can do this, however (it requires using conditional directives, which you can't just "call" in a macro). Macros *can* do math, but that requires macro-friendly forms like `LOGAND((F,F,F,F,F,F,0,0),SUB((3),GL_TEXTURE0))` where hex numbers are re-represented as `(x,y,z)` (and basically you *implement* math, so it's a lot of work)... – H Walters Apr 24 '19 at 03:36
  • ...so if you want an actual, working implementation, it's critical that your question is as nit picky as possible. So... basically, you can't *evaluate expressions* using *macros*; but, do you want to *evaluate expressions* using the *preprocessor*, or *do arithmetic* using *macros*? – H Walters Apr 24 '19 at 03:37
  • Possible duplicate of [Can the C preprocessor perform integer arithmetic?](https://stackoverflow.com/questions/1560357/can-the-c-preprocessor-perform-integer-arithmetic) – ichster May 02 '19 at 01:02

2 Answers2

2

Your first code sample should work, so it is not necessary to paste string literals together in the preprocessor. It is also not possible.

It is not possible because ## pastes together two preprocessing tokens, and the result must be a valid preprocessing token. A preprocessing token is a header name, identifier, preprocessing number, character constant, string literal, punctuator, or single non-white-space character. You cannot paste together two string literals and remove the two quote marks that end up between them. However, it is usually unnecessary to paste them together; simply letting them expand next to each other suffices because adjacent string literals are concatenated.

Your first code sample, which generates results like "tex" "0" is fine. After preprocessing and before analysis and translation (compilation), adjacent string literals are converted to a single concatenated string literal. So there will not be any problems of precedence or other syntax and semantics.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Note: This address only the concatenation of string literals. If there is a problem expanding `unit` to a desired string literal, that is not addressed—that problem is not explained clearly in the question. – Eric Postpischil Apr 24 '19 at 00:17
  • TY for the answer. Made some updates to the original post. I am not so much looking for a reason why my examples don't work, but rather I am having trouble using arithmetic inside macros to create a string literal. – ichster Apr 24 '19 at 01:25
  • 1
    @ichster: You won't be able to use arithmetic inside the macros — the preprocessor does text substitution, not arithmetic. (It does arithmetic in `#if` and `#elif` conditions, but not otherwise.) – Jonathan Leffler Apr 24 '19 at 05:04
  • @JonathanLeffler You're confusing evaluating constant expressions with [doing arithmetic](http://coliru.stacked-crooked.com/a/5233d485a50787c3). – H Walters Apr 24 '19 at 16:24
  • @HWalters — hmmm; I regard constant expressions as arithmetic (at least when there are arithmetic operators involved — that's a subset of the possibilities for expressions that can be evaluated by the preprocessor. But I was commenting and giving a useful succinct abbreviated term for what goes on, not giving a definitive answer. – Jonathan Leffler Apr 24 '19 at 17:08
0

I wanted to wrap up this question for future viewers by referencing a question that already answers this question: Can the C preprocessor perform integer arithmetic?

In short, the pre-processor can do arithmetic if it is used in when evaluating constant conditions:

#if 1 + 2 == 5
#endif
#else
#endif

But since you can't combine a macro with this you can't make make string literal definitions before compiling.

ichster
  • 23
  • 5
  • "But since you can't combine a macro with this" ...[why not](https://repl.it/repls/PeachpuffGrayAutomatedinformationsystem)? (in the repl run (and feel free to examine) main.sh; this is simply a hex version of [boost slots](https://www.boost.org/doc/libs/1_70_0/libs/preprocessor/doc/ref/slot.html); and is what I mean by "evaluating expressions using the preprocessor" to solve this problem). – H Walters May 02 '19 at 05:04