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 ?

Bob
  • 4,576
  • 7
  • 39
  • 107

4 Answers4

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 } };
}
Ron
  • 14,674
  • 4
  • 34
  • 47
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)};
user7860670
  • 35,849
  • 4
  • 58
  • 84
  • Since this works, why isn't it possible to declare an array inside the `{}`? – Bob Nov 02 '17 at 13:21
  • 3
    @Adrian - Because C++ doesn't allow. You can't force the language to be something it's not. – StoryTeller - Unslander Monica Nov 02 '17 at 13:24
  • This solution is much more in-line with the task of converting existing C code to C++ than the highest-voted one. – Jeffrey Nov 02 '17 at 13:31
  • @Jeffrey - No offence to this answer, but how do you reckon this is more inline? – StoryTeller - Unslander Monica Nov 02 '17 at 13:38
  • 1
    @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 Nov 02 '17 at 13:47
  • 2
    @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. – StoryTeller - Unslander Monica Nov 02 '17 at 13:52
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}};
DeepakKg
  • 349
  • 2
  • 4
  • `initializer_list` doesn't offer `operator[]`. The OP won't be able to use it as a drop in replacement. – StoryTeller - Unslander Monica Nov 02 '17 at 13:39
  • 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 – DeepakKg Nov 02 '17 at 13:51
  • 1
    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. – StoryTeller - Unslander Monica Nov 02 '17 at 13:55
  • 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 – Massimiliano Janes Nov 02 '17 at 14:30
  • 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) – DeepakKg Nov 02 '17 at 14:41
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 )

Massimiliano Janes
  • 5,524
  • 1
  • 10
  • 22