5

How do I combine pre-defined C values to generate a string.

#define APP_NUMBER 22
#define ICON_FILE  "../icons/"##APP_NUMBER##".ico"

so that in my .rc file I can do the following

 1000 ICON  ICON_FILE

instead of 1000 ICON "../icons/22.ico"

it didnt work

  #define MY_ICON_FILE 25
  #define STR(x) #x
  #define ICON_FILE_NUM(x) "../icons/" STR(x) ".ico"
  1000 ICON  ICON_FILE_NUM(MY_ICON_FILE)

compiler error

  can't open icon file `../icons/': Permission denied

  nothing was appended to "../icons/"

the closest I just got was by doing this:

  #define MY_ICON_FILE 25
  #define STR(x) #x
  #define ICON_FILE_NUM(x) "../icons/"STR(x)".ico" /// took out spaces
  1000 ICON  ICON_FILE_NUM(MY_ICON_FILE)

( taking out the spaces around STR(x) )

and got this compiler error

 can't open icon file `../icons/"25".ico': Invalid argument
3
  • Is this really a question about resource files, and not C? Commented Nov 22, 2012 at 5:27
  • I don't think this is a question about C. Maybe if you retagged the question you would get a better answer. Commented Nov 22, 2012 at 5:39
  • What exactly is a .rc file? I guess it's some kind of resource file, but what kind? What environment are you using? Commented Nov 22, 2012 at 6:19

4 Answers 4

5

This works:

#define APP_NUMBER 22
#define STR(x) #x
#define ICON_FILE_NAME(num)  "../icons/" STR(num) ".ico"
#define ICON_FILE ICON_FILE_NAME(APP_NUMBER)

#include <stdio.h>
int main(void) {
    printf("ICON_FILE = \"%s\"\n", ICON_FILE);
    return 0;
}

The output is:

ICON_FILE = "../icons/22.ico"

But the ICON_FILE macro expands to "../icons/" "22" ".ico", which is valid syntax for C (adjacent string literals are concatenated), but probably not for a .rc file, which explains the "can't open icon file" message you're getting.

It looks like you're trying to use token-pasting to generate a string literal. The problem with that is that a partial string literal, containing an unmatched " character, cannot be a valid preprocessing token. For example, you can't pass a single " as an argument to a macro.

Consider writing a program (script, whatever) that generates the appropriate #define directives for you.

Sign up to request clarification or add additional context in comments.

3 Comments

It looks like this (string literals not concatenated by the resource compiler) is indeed the case, unfortunately: stackoverflow.com/a/11161985/163956
ok but how does it work in a RC file ( resource ) at the moment i have 1000 ICON "../icons/59.ico" resource number 1000 is this icon, but i want to do 1000 ICON ICON_FILE
@AshodApakian: "Resource files" are not a feature of the C language. If you want help with them, you'll need to tell us what environment you're using. See my comment on the question.
1

Windows resource files don't understand the C style literal string concatenation for most elements - string table may be the only exception.

The trick when working with pre-processor macros is then to not use strings as input starting point, the pre-processor doesn't know how to remove quotes.

It would also be helpful to concatenate only once - consider addition of search paths "-I../icons/" rather than adding paths to the resource names.

Pulled the following from boost, example using windows msvc which is using an additional level of indirection than what I have seen in most places.

#    define BOOST_PP_CAT(a, b) BOOST_PP_CAT_OO((a, b))
#    define BOOST_PP_CAT_OO(par) BOOST_PP_CAT_I ## par
#    define BOOST_PP_CAT_I(a, b) a ## b

#    define BOOST_PP_STRINGIZE(text) BOOST_PP_STRINGIZE_A((text))
#    define BOOST_PP_STRINGIZE_A(arg) BOOST_PP_STRINGIZE_I arg
#    define BOOST_PP_STRINGIZE_I(text) #text

In examples seems you could just perform BOOST_PP_CAT(../icons/, BOOST_PP_CAT(num,.ico))

There is an issue passing to stringize only the outer CAT is applied (On windows at least). So BOOST_PP_STRINGIZE(BOOST_PP_CAT(../icons/, BOOST_PP_CAT(num,.ico))) doesn't work.

Addition for concatenation of 3 items

#    define BOOST_PP_CAT2(a, b, c) BOOST_PP_CAT_OO2((a, b, c))
#    define BOOST_PP_CAT_OO2(par) BOOST_PP_CAT_I2 ## par
#    define BOOST_PP_CAT_I2(a, b, c) a ## b ## c

In my testing VS2013 an input of

  • .. is being converted to "..." which makes working with relative path difficult
  • \ needs to be escaped \\ to work in macro args, but is being converted to "\\" - using / for path works better

Working against the string table can be easier to see output than working with icons

STRINGTABLE
BEGIN
  123  BOOST_PP_STRINGIZE(BOOST_PP_CAT(APP_NUMBER, .ico))
  124  BOOST_PP_STRINGIZE(BOOST_PP_CAT2(../icons/, APP_NUMBER,.ico)))
END

I haven't yet worked out resolution of .. being converted to ... I had the following work using the additional search path,

1000        ICON        BOOST_PP_STRINGIZE(BOOST_PP_CAT(APP_NUMBER, .ico))
1001        ICON        BOOST_PP_STRINGIZE(BOOST_PP_CAT2(icons/, APP_NUMBER, .ico))

Comments

-1

I would honestly avoid doing this using preprocessor. Debugging preprocessor errors is a pain and I've seen cases where multiple layers of preprocessor replacements and concatenations were used, resulting in disaster when trying to find issues. Just my 2 cents.

Comments

-1

I don't think you will be able to do it with C pre-processor. However, you could do it with m4 pre-processor.

linux_prompt> cat icon.m4
define(APP_NUMBER, 22)

1000 ICON "../icons/APP_NUMBER.ico"

linux_prompt> m4 icon.m4

1000 ICON "../icons/22.icon"

You have to make sure that the rest of the file expands correctly. Do 'man m4' for more info.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.