9

Hello I have the following test code and I am confused about cpp.

  1. If you declare in library.h an array with an empty element clause .. what will the compiler pick? It does also not complain, I use Cygwin.

  2. In library.cpp I assign values to two elements, is the compiler assuming an array with one element and I write the second element outside the scope of the array?

library.h

#ifndef LIBRARY_H
#define LIBRARY_H

class library {

public:
    void print();
    char a[];
};

#endif

library.cpp

#include <stdio.h>
#include "library.h"

void library::print() {
    a[0] = 'a';
    printf("1. element: %d\n", a[0]);
    a[1] = 'b';
    printf("2. element: %d\n", a[1]);
}

client.cpp

#include <stdio.h>
#include "library.h"

void execute();
library l;

int main() {
    l = library();
    l.print();
    return 0;
}

Makefile

OPTIONS=-Wall

all: main

run: main
        ./main.exe

main: client.o library.o
        g++ $(OPTIONS) -o main $^

library.o: library.cpp library.h
        g++ $(OPTIONS) -c $<

.cpp.o:
        g++ $(OPTIONS) -c $<

clean:
        rm -r *.o
Andrew Surzhynskyi
  • 2,726
  • 1
  • 22
  • 32
user2050516
  • 760
  • 2
  • 5
  • 15

4 Answers4

11
  1. There is no language called C/C++, So your Q cannot be tagged with both.
  2. Since you are using classes, Your program can only be C++ and not C.

public:
     void print();
     char a[];

This code is simply illegal in C++. Array size in C++ needs to be positive compile time constant. Solution is to replace it by:

public:
      void print();
      std::string a;

Note that the declaration,

char a[];

is valid in c99 and it is known as Incomplete array type, the C standard guarantees that a can store atleast one element of the type char. This is not valid in C++. C++ standard does not allow these. Simply because both are different languages.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • When you make it a string, this `a[0]='a';` doesn't work. replace with `a="ab"`, then you can access as `a[0]` and `a[1]` in the `printf` statement – balki Mar 19 '13 at 08:51
  • @balki: Why `printf`? Why not `std::cout`? – Alok Save Mar 19 '13 at 08:52
  • 5
    The declaration `char a[]` is legal in C++ as well, and is also an incomplete array type. The difference is that in C++, _all_ class members must be complete types; in C98 (but not C90), there is a special exception which allows the _last_ element of a struct to be an incomplete array type (with restrictions on what you can do with the resulting struct). And the compiler does _not_ reserve any memory for it; the size of the struct is as if this element were not there (unless it increases the alignment requirements of the struct). – James Kanze Mar 19 '13 at 08:56
  • @balki You can't assign to it, since it has array type. (In his case, you can't assign to the array members either, since they don't exist.) – James Kanze Mar 19 '13 at 08:57
6

First, it's not legal C++. It's an old hack, which C only made legal in C98. The basic idea is that such struct can only be dynamically allocated (using malloc), and you allocate however much memory is needed for the object after it. So you'll do something like malloc( sizeof( library ) + strlen( s ) + 1 ). The hack is used to avoid an extra allocation.

A class which uses this hack cannot be used with new, nor can it be a member or a base class. (It cannot be a member in C, either.)

You can sort of emulate this in C++:

class Library
{
    //  ...
    char* buffer() { return reinterpret_cast<char*>( this + 1 );
    void* operator new( size_t n, size_t extra )
    {
        assert( n == sizeof( Library ) );
        return ::operator new( n + extra );
    }
};

Note, however, that unlike the C solution, this runs the risk of alignment problems. It works fine for character types, and it will work if other members of the class require at least as much alignment as the buffer type, but it can fail otherwise. (The implementation of std::basic_string in g++ uses it—and will crash on some machines if instantiated with double.)

James Kanze
  • 150,581
  • 18
  • 184
  • 329
5

The empty array declares a zero-length array. It is used in C by placing a structure S in a memory zone bigger than sizeof(S) and then using the array to access the remaining memory:

memory* ptr = malloc(sizeof(memory) + sizeof(char) * 10);
// you can now manipulate ptr->a as an array of 10 elements

This is a trick that is a lot less useful in C++. Simply use std::vector instead.

sylvain.joyeux
  • 1,659
  • 11
  • 14
  • 1
    Nor is it a "trick". It is called a *flexible array member*, and is documented in the C99 standard, specifically C99 §6.7.2.1-p18, and as Armen pointed out, it is non-standard to C++. – WhozCraig Mar 19 '13 at 08:35
1

It's commonly referred to as the struct hack in C. It uses a feature called flexible array member.

This is however not part of any C++ standard specification. Have a look at this question.

Note that the observation that something apparantly does work does not imply that you can rely on it to work reliably. If the behavior is undefined, technically anything can happen. Including raptors suddenly attacking.

In C++ you probably would use a std::vector<char> or a std::string instead.

Community
  • 1
  • 1
moooeeeep
  • 31,622
  • 22
  • 98
  • 187