Nicola Mori
Nicola Mori

Reputation: 889

Flexible array error with gcc 6 but not with gcc 4

I'm trying to compile a piece of code written by a colleague. On my machine with gcc 6.1.1 I get this error:

In file included from src/TYAGlobalLibs.cc:1:0:
./include/TYAGlobalLibs.hh:112:17: error: flexible array member ‘TYA::TMultiHist::fh’ not at end of ‘class TYA::TMultiHist’
 TH1F    *fh[];
             ^
./include/TYAGlobalLibs.hh:102:9: note: in the definition of ‘class TYA::TMultiHist’
class TMultiHist{
      ^~~~~~~~~~

It seems that this is a forbidden code path and as such it triggers a compiler error; however, using gcc 4.5.2 the same file compiles without error. I use these compiler options for g++:

-O2 -Wall -fPIC -pthread -m32 -std=c++98

for both 6.1.1 and for 4.5.2. In case it matters, gcc 6 runs on a 64 bit machine while gcc 4 on a 32 bit one. Here's a minimal code snippet to reproduce the issue:

struct test{
        int a;
        float b[];
        double c;
};

int main(){     
}

Does anybody know why this happens and eventually if there are compiler options to make gcc 6 compile without errors (I have no chance of changing the code, it's not under my control)?

Upvotes: 2

Views: 1979

Answers (1)

Keith Thompson
Keith Thompson

Reputation: 263307

In C (C99 and later), a flexible array member can be defined with [], and must be the last member of a structure. C++ doesn't support flexible array members, but g++ permits them as a language extension.

Older versions of g++ do not require a flexible array member to be the last member of a class or struct. This is a bug, which has been corrected in newer versions of g++.

Here's a small test program, based on yours that illustrates the problem:

#include <iostream>
#include <cstddef>

static int mem[100];

struct test{
        int a;
        int b[];
        int c;
};

int main(){     
    test *ptr = (test*)&mem;
    ptr->a = 10;
    ptr->b[0] = 20;
    ptr->b[1] = 30;
    ptr->c = 40;

    std::cout << "ptr->a    = " << ptr->a << "\n";
    std::cout << "ptr->b[0] = " << ptr->b[0] << "\n";
    std::cout << "ptr->b[1] = " << ptr->b[1] << "\n";
    std::cout << "ptr->c    = " << ptr->c << "\n";
}

And here's the output when I compile it with g++ 4.1.2:

ptr->a    = 10
ptr->b[0] = 40
ptr->b[1] = 30
ptr->c    = 40

As you can see, the member c is allocated at the same offset as b[0].

(Strictly speaking, using an int[] array to hold a test object isn't 100% safe due to possible alignment problems, but that's unlikely to be an issue in practice.)

It's very likely that your code has undiscovered bugs because of this.

Your problem is not that the newer g++ rejects your code; it's that the older one doesn't.

Reordering the member declarations so the flexible array member appears last is the simplest fix -- though you (or someone else) will need to carefully examine how the type is used. A far better solution is probably to replace the flexible array member with some C++ container class, perhaps a std::vector.

(I have no chance of changing the code, it's not under my control)

Somebody is able to change the code, and presumably you're able to submit a bug report.

Upvotes: 1

Related Questions