2

I'm doing some low-level programming. For purpose of my task I need to initialize (sometimes hardware-limited) array. It can be just char[], but also unsigned short or whatever.

Most readable way is to use just some string of constant, known length. To ease the task I've wrote a macro to help myself.

#define INI( x ) { (x[0] << 8) | 0x00, (x[1] << 8) | 0x00 }

static const unsigned int tab[] = INI("ab");

int main(){
    return 0;
}

Of course macro above is inside some #ifdef block and depends on architecture it's being build on. The problem I have is that I'm getting error:

initializer element is not constant
main.c:3: error: (near initialization for "tab[0]")
initializer element is not constant
main.c:3: error: (near initialization for "tab[1]")

But above code expands to:

static const unsigned int tab[] = { ("ab"[0] << 8) | 0x00, ("ab"[1] << 8) | 0x00 };


int main(){
    return 0;
}

Each and EVERY element is not only constant at compile time, but also at preprocessor time. It could be even possible to create macro taking every character from the string and doing some manipulation (if only preprocessor would be able to get length of the string and would have some looping option of course).

So - why compiler isn't able to extract this information and what are my options? Any help is sincerely appreciated.

PS. I know that it works inside main() as

const unsigned int tab[] = INI("ab");

but I need it outside any function.

4
  • I can get this to compile OK using DevStudio 2010. EDIT: Actually, that's the C++ compiler that works. Commented Sep 13, 2011 at 15:24
  • @Throwback1986 - C99 of course. Sorry for not specifying it. I've just assumed that this version will be considered. Commented Sep 13, 2011 at 18:18
  • What's the point in oring with 0 in | 0x00? Commented Sep 13, 2011 at 18:31
  • @Jens - heh good spot :), it's just leftover from more complex macro with second argument - i.e. sometimes it's not 0x0. OTOH I find it also more readable - it reminds that there is still another byte in the pack. Commented Sep 13, 2011 at 18:45

2 Answers 2

1

You cannot do string subscripting / indexing in the preprocessor. What you could do is change the macro a bit:

#define ROW( x, y ) { ((x) << 8) | 0x00, ((y) << 8) | 0x00 }

static const unsigned int tab[] = ROW('a' , 'b');
Sign up to request clarification or add additional context in comments.

4 Comments

It's nothing to do with the preprocessor, or with array initialisers. static const char foo = "ab"[0]; doesn't work either.
Yes that is obvious. But you cannot get around it by trying to solve it in the preprocessor.
@wildplasser - You can do such thing but inside function. Thanks for your advice but unfortunately this is not acceptable. I'm getting lot's of parameters (at compile time) inside char* strings with known length. Sometimes char[] is enough but sometimes I need put those data inside uint16 or uint32 with some bit-shifting. Unfortunately preprocessor doesn't allow me to iterate over every character inside string or in easy way transform "data" into 'd','a','t','a' (cause I could later iterate over this). OTOH adding some compilation-time scripting may be not accepted by customer build system.
There should be backticks in the preprocessor. I think you can choose 2 options: 1) generate code which is later included 2) accept the strings "as is" as input and process them later, during initialisation. This would imply that some of your definitions "unsigned int tab[];" need to be changed to either oversized or dynamically allocated. plus: you'd need to keep track of their sizes.
0

Assuming it's C99, the standard says:

The expressions in this compound literal are required to be constant.

in reference to an example of a pointer with file scope. It is not sufficient for you to have an expression with constant variables - turns out the expression(s) must be constant as well.

7 Comments

Yeah. But then why it's allowed inside function? It doesn't really makes sense to me. It's not consistent. Sometimes I think that just a little bit effort could make C itself so good language that even C++ wouldn't be necessary. But having it's parts so terribly mangled makes me often really not use but fight this language.
A name has file scope if it's declaration is outside any block/function. If it's declared in the main method, then it's inside a block, so it does not have file scope.
still it doesn't make sense. Expression itself is (by the way) constant. Just little bit more expressive than 2+2*2. I guess accepting it and moving forward is best solution :)
in C, the only expressions that are constant are literals (like 1) and string literals (like "ab"). That's it. Subscripting is not considered a constant expression for the purposes of the compiler
@Foo Bath - then why it IS constant for the purposes of the compiler when used inside function?
|

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.