structure initialization refused by pocc

Started by japheth, June 16, 2009, 10:34:09 PM

Previous topic - Next topic

japheth


Hello,

I tried to compile JWasm with PellesC. Almost everything compiles without errors, with one exception. The issue is the initialization of a structure which contains 2 bitfields and a character array of "unknown" size:



#include <stdio.h>

typedef unsigned int uint_32;
typedef unsigned char uint_8;

typedef struct line_item {
    struct line_item *next;
    uint_32 lineno:20, srcfile:12;
    uint_32 list_pos; /* position .LST file */
    uint_8 macrolevel; /* just a bit (macrolevel > 0?) is needed */
    char line[];
} line_item;

line_item endl = { NULL, 0, 0, 0, 0, "END" };


pocc complains:

main3.c(15): warning #2213: Multiple initializers for the same element (at offset 13).
main3.c(15): error #2139: Too many initializers.

while MSVC, OW and gcc don't see a problem.

How is this supposed to be defined in Pelles C ?


Robert

I would guess that

uint_32 lineno:20, srcfile:12;

is not being parsed as expected

Does

uint_32 lineno:20;
uint_32 srcfile:12;

compile with Pelle's C without warning or error?

Robert Wishlaw

AlexN

I have tried something with your code. I my opion the error message are not related to the bitfields (when you remove the bitfield size you get the same error message). The problem seem to be the empty char array. If you use an empty string instead of "END" it compiles.
But at the moment I have no good solution for you. Is it possible to use a pointer to the char array?
best regards
Alex ;)

japheth

Quote from: AlexN on June 17, 2009, 07:56:14 AM
But at the moment I have no good solution for you. Is it possible to use a pointer to the char array?

No, that's not an option. There's a workaround, of course, but since the item's size is actually defined by the length of the <line> member, it's rather ugly and needs dynamic allocation:


#ifdef __POCC__
       line_item *endl = AsmAlloc( sizeof( line_item ) + 4 );
       endl->next = NULL;
       endl->srcfile = 0;
       endl->lineno = LineNumber;
       endl->list_pos = 0;
       strcpy( endl->line, "END");
       LineStoreHead = endl;
#else
       endl.lineno = LineNumber;
       LineStoreHead = &endl;
#endif


JohnF

Can't you declare the string var to have the right size?


typedef struct line_item {
    struct line_item *next;
    uint_32 lineno:20, srcfile:12;
    uint_32 list_pos; /* position .LST file */
    uint_8 macrolevel; /* just a bit (macrolevel > 0?) is needed */
    char line[4];
} line_item;


John

japheth

Quote from: JohnF on June 17, 2009, 11:45:43 AM
Can't you declare the string var to have the right size?

No, it's variable. The sample which I posted is a test case only.

AlexN

Quote from: japheth on June 18, 2009, 10:03:10 AM
No, it's variable. The sample which I posted is a test case only.

I think this is also no good solution for your example?


char line[] = {"\0\0\0\0\0\0\0\0\0\0\0\0\0END"};
line_item *uendl = (line_item *)line;

:)
best regards
Alex ;)

JohnF

#7
Quote from: japheth on June 18, 2009, 10:03:10 AM
Quote from: JohnF on June 17, 2009, 11:45:43 AM
Can't you declare the string var to have the right size?

No, it's variable. The sample which I posted is a test case only.

From the original code.


void StoreLine( char * string )
{
   int i;

   i = strlen(string) + 1;
   LineStoreCurr = AsmAlloc( i + sizeof(line_item) );
   LineStoreCurr->next = NULL;
   LineStoreCurr->lineno = LineNumber;
   LineStoreCurr->list_pos = list_pos;
   LineStoreCurr->macrolevel = MacroLevel;
   memcpy( LineStoreCurr->line, string, i );
   LineStoreTail->next = LineStoreCurr;
   LineStoreTail = LineStoreCurr;
}



Even the original has to allocate for a string of unknown length. The most elegant way would be to make a func that deals with this issue.

EDIT: Here's a page on 'flexible array members' which is what you are using.

http://books.google.co.uk/books?id=iRa-3L4jLhEC&pg=PA554&lpg=PA554&dq=flexible+array+member&source=bl&ots=dXiybr7a3K&sig=1BM5U1NosUCz_5w1YZpG80G9Xd0&hl=en&ei=Yk46So7-NJm6jAe_zvimDQ&sa=X&oi=book_result&ct=result&resnum=7

John


Seltsamuel

Hi,

no time to test but this should really work ;-)

#include <stdio.h>

typedef unsigned int uint_32;
typedef unsigned char uint_8;

typedef struct line_item {
    struct line_item *next;
    uint_32 lineno:20, srcfile:12;
    uint_32 list_pos; /* position .LST file */
    uint_8 macrolevel; /* just a bit (macrolevel > 0?) is needed */
    char *line;
} line_item;

line_item endl = { NULL, 0, 0, 0, 0, "END" };

Greetings

Seltsamuel

AlexN

Quote from: Seltsamuel on June 18, 2009, 11:29:56 PM
no time to test but this should really work ;-)

#include <stdio.h>

typedef unsigned int uint_32;
typedef unsigned char uint_8;

typedef struct line_item {
    struct line_item *next;
    uint_32 lineno:20, srcfile:12;
    uint_32 list_pos; /* position .LST file */
    uint_8 macrolevel; /* just a bit (macrolevel > 0?) is needed */
    char *line;
} line_item;

line_item endl = { NULL, 0, 0, 0, 0, "END" };

I think also this is a good solution, but japheth don't like it. :(

So I would prefer a constructor like:


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

typedef unsigned int uint_32;
typedef unsigned char uint_8;

typedef struct line_item {
    struct line_item *next;
    uint_32 lineno:20, srcfile:12;
    uint_32 list_pos; /* position .LST file */
    uint_8 macrolevel; /* just a bit (macrolevel > 0?) is needed */
    char line[];
} line_item;

line_item *endl;

line_item *create_line_item(line_item *next, uint_32 srcfile, uint_32 lineno, uint_32 list_pos, uint_8 macrolevel, char * string )
{
        line_item *litem = (line_item *)malloc( sizeof( line_item ) + strlen(string) + 1 );
        litem->next = next;
        litem->srcfile = srcfile;
        litem->lineno = lineno;
        litem->list_pos = list_pos;
        litem->macrolevel = macrolevel;
        strcpy( litem ->line, string);
        return litem;
}

void destroy_line_item(line_item *li)
{
if (li != NULL)
{
free(li);
}
}

int main(int argc, char *argv[])
{
endl = create_line_item( NULL, 0, 0, 0, 0, "END" );
printf("%s\n", endl->line);
destroy_line_item(endl);
return 0;
}



Alex ;)

best regards
Alex ;)

nicolas.sitbon

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

typedef struct line_item
{
   struct line_item * next;
   uint32_t lineno  :20;
   uint32_t srcfile :12;
   uint32_t list_pos;   /* position .LST file */
   uint8_t  macrolevel; /* just a bit (macrolevel > 0?) is needed */
   char     line[];
}
line_item;

static line_item *create_line_item(line_item const * item, char const * line)
{
   size_t line_size  = strlen(line) + 1;
   line_item * litem = malloc(line_size + sizeof *litem);

   if(litem != NULL)
   {
      *litem = *item;
      memcpy(litem->line, line, line_size);
   }

   return litem;
}

static inline void destroy_line_item(line_item * item)
{
   free(item);
}

int main(void)
{
   line_item * endl = create_line_item(&(line_item){NULL, 0, 0, 0, 0}, "END");
   puts(endl->line);
   destroy_line_item(endl), endl = NULL;

   return 0;
}

Pelle

The last member (line) is what the C standard calls a "flexible array member" - this was added in C99. AFAIK, initialization of a structure with a flexible member stops just before such a member - the error is correct (and the warning is just noice). Before C99, this was an extension in several C compilers which may or may not agree on the behaviour...
/Pelle