tags:

views:

1765

answers:

10

I want to do the following

char a[] = { 'A', 'B', 'C', 'D'};

But I do not want to write these characters separately. I want something like

#define S "ABCD"

char a[] = { S[0], S[1], S[2], S[3] };

But this won't compile (gcc says 'initializer element is not constant').

I tried replacing the #define line with

const char S[] = "ABCD";

But that doesn't seem to help.

How can I do this (or something similar) that lets me write the "ABCD" as a normal 'string', and not as four separate characters?

P.S. It seems that people do not read the question correctly...

I can't get the following code to compile:

const char S[] = "ABCD";
char t[] = { S[0], S[1], S[2], S[3] };
char u[] = { S[3], S[2], S[1], S[0] };
+2  A: 

Simply

const char S[] = "ABCD";

should work.

What's your compiler?

Mehrdad Afshari
Note that this initializes a 5-element array. There's also the \0 at the end. If you don't want it, make it a const char S[sizeof("ABCD")-1] = "ABCD"
laalto
Yes, just specifying the size to 4 will make the compiler omit the \0. The choice depends on what you actually want to do.
Mehrdad Afshari
Did you try this? I tried it with- ARM ADS 1.2 and gcc (for x86), and the result is the same: both compilers complain that the input **is not** const.
Arnaud Gouder
I just tested this with Leopard gcc 4.0.1 for x86 and worked perfectly. It's in the standard. If it doesn't work, I count the compiler as broken.
Mehrdad Afshari
See the other answer on this question: It's not this line that does not build! It's if you add a line 'char t[] = { S[0], S[1] };' that I can't get to work.
Arnaud Gouder
I guess you should clarify that in the question. By the way, that works too if you declare it in a *function* but won't work as a global variable. I'm thinking of a workaround but couldn't find one so far.
Mehrdad Afshari
A: 

This compiles fine on gcc version 4.3.3 (Ubuntu 4.3.3-5ubuntu4).

const char s[] = "cheese";

int main()
{
    return 0;
}
Ranieri
Duh :-)But please add a line char t[] = { s[0], s[1] };because that is what I'm trying to do!
Arnaud Gouder
Arnaud: So your problem is with that line. Why do you want to do that? What exactly you're trying to accomplish?
Mehrdad Afshari
I want to have TWO char arrays, with the same contents, but in a differnt order. And this order is know at compile time, so I don't want to do any shuffling at runtime!
Arnaud Gouder
A: 

Perhaps your character array needs to be constant. Since you're initializing your array with characters from a constant string, your array needs to be constant. Try this:

#define S "ABCD"
const char a[] = { S[0], S[1], S[2], S[3] };
Shakedown
Thanks, but no. I tried this and get the same error, which is logical, because the compiler complains that my 'initialization elements' are not const!
Arnaud Gouder
Hm, but "ABCD"[0] should return a const character, right?
Shakedown
It should, that's why I don't understand that it doesn't work :-)
Arnaud Gouder
As it happens, literal strings are char* in C, not const char*, so "ABCD"[0] doesn't evaluate to a const char. However that's not the problem - global initializers have to be constant expressions. That's a separate concept from whether a value is const.
Steve Jessop
A: 
const char S[] = "ABCD";

This should work. i use this notation only and it works perfectly fine for me. I don't know how you are using.

Meetu Choudhary
Apparently I didn't phrase my question very clearly.Try to compile the following **two** lines:const char S[] = "ABCD"; char t[] = { S[0], S[1] };
Arnaud Gouder
and whats the need for that did char s[] ="ABCD" alone wont work for you? what is the exact requirement
Meetu Choudhary
A: 

Here is obscure solution: define macro function:

#define Z(x) \
        (x==0 ? 'A' : \
        (x==1 ? 'B' : \
        (x==2 ? 'C' : '\0')))

char x[] = { Z(0), Z(1), Z(2) };
Move them outside the `main` function. They won't work as global vars.
Mehrdad Afshari
It's exactly as Mehrdad says: my problem occurs not within a function, but when these variables are global (or static, but not part of a function)
Arnaud Gouder
@Mehrdad, @Arnaud: Ok, I see. I now changed the solution to another one.
Nice, but an even simpler solution would be #define Z0 'A', #define Z1 'B', etc... And that is exactly my starting point that I didn't like :-)
Arnaud Gouder
Hehe nice :) If you would define Z0, Z1, etc. as "A", "B", etc. (notice double quotes) then you wouldn't have to use commas in initializer, simple char x[] = {Z1 Z2 Z3 } would work.
A: 

Weird error.

Can you test this?

const char* const S = "ABCD";
char t[] = { S[0], S[1], S[2], S[3] };
char u[] = { S[3], S[2], S[1], S[0] };
Nick D
Tried that already. Doesn't work also.
Arnaud Gouder
A: 

I'm not sure what your problem is, but the following seems to work OK:

#include <stdio.h>

int main()
{
    const char s0[] = "ABCD";
    const char s1[] = { s0[3], s0[2], s0[1], s0[0], 0 };

    puts(s0);
    puts(s1);
    return 0;
}


Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.10.3077 for 80x86
Copyright (C) Microsoft Corporation 1984-2002. All rights reserved.
cl /Od /D "WIN32" /D "_CONSOLE" /Gm /EHsc /RTC1 /MLd /W3 /c /ZI /TC
   .\Tmp.c
Tmp.c
Linking...

Build Time 0:02


C:\Tmp>tmp.exe
ABCD
DCBA

C:\Tmp>

Edit 9 June 2009

If you need global access, you might need something ugly like this:

#include <stdio.h>

const char *GetString(int bMunged)
{
    static char s0[5] = "ABCD";
    static char s1[5];

    if (bMunged) {
        if (!s1[0])  {
            s1[0] = s0[3]; 
            s1[1] = s0[2];
            s1[2] = s0[1];
            s1[3] = s0[0];
            s1[4] = 0;
        }
        return s1;
    } else {
        return s0;
    }
}

#define S0 GetString(0)
#define S1 GetString(1)

int main()
{
    puts(S0);
    puts(S1);
    return 0;
}
Michael J
It wont work if s1 will be global.
This answer was tried already :-) The problem is that the array should be global!
Arnaud Gouder
A: 

The compilation problem only occurs for me (gcc 4.3, ubuntu 8.10) if the three variables are global. The problem is that C doesn't work like a script languages, so you cannot take for granted that the initialization of u and t occur after the one of s. That's why you get a compilation error. Now, you cannot initialize t and y they way you did it before, that's why you will need a char*. The code that do the work is the following:

#include <stdio.h>
#include <stdlib.h>

#define STR "ABCD"

const char s[] = STR;
char* t;
char* u;

void init(){
    t = malloc(sizeof(STR)-1);
    t[0] = s[0];
    t[1] = s[1];
    t[2] = s[2];
    t[3] = s[3];


    u = malloc(sizeof(STR)-1);
    u[0] = s[3];
    u[1] = s[2];
    u[2] = s[1];
    u[3] = s[0];
}

int main(void) {
    init();
    puts(t);
    puts(u);

    return EXIT_SUCCESS;
}
Sambatyon
+6  A: 

You can't - in C. In C initializing of global and local static variables are designed such that the compiler can put the values statically into the executable. It can't handle non-constant expressions as initializers. And only in C99, you can use non-constant expression in aggregate initializers - not so in C89!

In your case, since your array is an array containing characters, each element has to be an arithmetic constant expression. Look what it says about those

An arithmetic constant expression shall have arithmetic type and shall only have operands that are integer constants, floating constants, enumeration constants, character constants, and sizeof expressions.

Surely this is not satisfied by your initializer, which uses an operand of pointer type. Surely, the other way is to initialize your array using a string literal, as it explains too

All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.

All quotes are taken out of the C99 TC3 committee draft. So to conclude, what you want to do - using non-constant expression - can't be done with C. You have several options:

  • Write your stuff multiple times - one time reversed, and the other time not reversed.
  • Change the language - C++ can do that all.
  • If you really want to do that stuff, use an array of char const* instead

Here is what i mean by the last option

char const c[] = "ABCD";
char const *f[] = { &c[0], &c[1], &c[2], &c[3] };
char const *g[] = { &c[3], &c[2], &c[1], &c[0] };

That works fine, as an address constant expression is used to initialize the pointers

An address constant is a null pointer, a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator; it shall be created explicitly using the unary & operator or an integer constant cast to pointer type, or implicitly by the use of an expression of array or function type. The array-subscript [] and member-access . and -> operators, the address & and indirection * unary operators, and pointer casts may be used in the creation of an address constant, but the value of an object shall not be accessed by use of these operators.

You may have luck tweaking your compiler options - another quote:

An implementation may accept other forms of constant expressions.

Johannes Schaub - litb
+1 great explanation and workaround.
Mehrdad Afshari
A: 

That's one of the cases a script to generate the appropriate code might help.

Markus Schnell