3

I have C-code that I need to compile to C++ and need to minimally change it.

In C, the following works

typedef struct _type_t
{
    int a;
    int b;
    int c[];
}type_t;

type_t var = {1,2,{1,2,3}};

But in C++11, it gives the error

error: too many initializers for int [0]

But I cannot give type_t.c a constant size because it needs to work for any size array.

So I need to change the struct to

typedef struct _type_t
    {
        int a;
        int b;
        int *c;
    }type_t;

But then I need to change

type_t var = {1,2,{1,2,3}};

to something else because current code gives the error

error: braces around scalar initializer for type int*

Casting 3rd element to(int[]) gives error

error: taking address of temporary array

This is from micropython, parse.c:

#define DEF_RULE_NC(rule, kind, ...) static const rule_t rule_##rule = { RULE_##rule, kind, #rule, { __VA_ARGS__ } };

How do I initialize the array and assign it to type_t.c ?

8
  • 1
    gcc warns with your C code: "warning: initialization of a flexible array member [-Wpedantic]" ( gcc -Wall -pedantic -std=c11 ) Commented Nov 2, 2017 at 13:15
  • 2
    You need to know the size of c to do this. For example, it would have worked if int c[]; was int c[3]; Commented Nov 2, 2017 at 13:17
  • 2
    @Adrian Why would it? C is not C++ is not C. Commented Nov 2, 2017 at 13:19
  • 3
    @Adrian - No, it doesn't work in C. It works under your previous compiler, which offered an extension. The C language specification explicitly forbids it. Commented Nov 2, 2017 at 13:25
  • 1
    @StoryTeller I guess you're right: it's not allowed by C standard but it works in gcc. Commented Nov 2, 2017 at 13:31

4 Answers 4

7

Use std::vector and aggregate initialization:

struct type_t
{
    int a;
    int b;
    std::vector<int> c;
};

int main() {
    type_t var = { 1, 2, { 1, 2, 3 } };
}
Sign up to request clarification or add additional context in comments.

6 Comments

That's not an option. I need to modify it as little as possible i.e. not introduce use of stl.
Sure it's an option. It's the preferred option.
then I have to modify all the code that uses type_t
@Adrian std::vector has operator[] overloaded, so you can, still, access the elements stored in a std::vector, as you would access array elements.
@Adrian then you'll need to accept that C++ is not C and there are things you will have to do differently than you did in C.
|
6

In order to do this you need to make your array really static:

typedef struct _type_t
{
    int   a;
    int   b;
    int * c;
}type_t;

int items[3] = {1,2,3};
type_t var = {1,2, static_cast< int * >(items)};

6 Comments

Since this works, why isn't it possible to declare an array inside the {}?
@Adrian - Because C++ doesn't allow. You can't force the language to be something it's not.
This solution is much more in-line with the task of converting existing C code to C++ than the highest-voted one.
@StoryTeller this leaves the memory footprint of the object indentical to what it was before. There's a chance that somewhere lurks an access to _type_t.c typcasted to int*. Or a memcpy of _type_t assuming a specific size. Or complexity in addind std::vector. I've converted legacy codebase before and typically, the less of change the better. Even if you end-up up with hackish stuff like that.
@Jeffrey - To be perfectly honest, the way I see this, the proper conversion is to keep compiling this as C with extensions. Just wrap it tightly and snugly in a standard compliant hazmat suit of code, and leave it be.
|
1

C++ doesn't allow this statement expression. You may use lightweight std::initialiser_list to achieve the objective

#include <initializer_list>
typedef struct _type_t
{
    int a;
    int b;
    std::initializer_list<int> c;
}type_t;

 type_t var = {1,2,{1,2,3,4}};

5 Comments

initializer_list doesn't offer operator[]. The OP won't be able to use it as a drop in replacement.
Story Teller : Yes it doesn't provide subscript and one has to use the iterator to traverse through it. But its very lightweight as compared to vector and depending upon one's requirement they may choose to use it
It's too lightweight I'm afraid. For one there's object lifetime considerations to think about. Is the member c going to prolong the life of the temporary array created from {1, 2, 3, 4}? I don't think it will. Since the OP also wants a drop in replacement, it doesn't go towards helping here.
it's also not lightweight enough, there's no guarantee that such a type_t remains POD; so even if it were correct, you'd gain very little over std::vector
I guess the requirements of the function / program should decided what to choose. Its an option, may not be the best for every situation, but memory and complexity wise its definitely better than the vector because there is no requirement of growing it dynamically (As per the code above)
0

yet another alternative might be

    ...
    int * c;
}type_t;

type_t var = {1,2, []{ static int x[] = {1,2,3}; return x; }() };

PS: yes, I know it's crazy, but it's somewhat more respectful of OP requirements ( it can be incorporated in a dropin replacement macro as given )

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.