- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
In integrating a third party C library into our product, I came across a fragment of code where inside a function, a struct is defined that includes a variable length array, the length of which depends on a parameter of that function. Incrementing a pointer s to such a struct works differently depending on whether you write ++s or s += 1 on the one hand, or s = s + 1 on the other hand. The code is similar to the following:
[cpp]#include <stdio.h>
typedef struct {
int ndim;
void *firstmember, *lastmember;
} Container;
#define N_MEMBERS 5
#define TYPEDEFMEMBER(t) \
typedef struct { \
int n; \
double data[t->ndim]; \
} Member
void init(Container *t) {
TYPEDEFMEMBER(t);
Member *first, *last;
first = malloc(N_MEMBERS * sizeof(Member));
last = first + N_MEMBERS - 1;
t->firstmember = first;
t->lastmember = last;
}
void process(Container *t) {
TYPEDEFMEMBER(t);
Member *s, *first, *last;
first = t->firstmember;
last = t->lastmember;
printf("t->ndim = %d, with ++s:\n", t->ndim);
for (s = first; s <= last; ++s) {
printf("s: %p\n", s);
}
printf("t->ndim = %d, with s += 1:\n", t->ndim);
for (s = first; s <= last; s += 1) {
printf("s: %p\n", s);
}
printf("t->ndim = %d, with s = s + 1:\n", t->ndim);
for (s = first; s <= last; s = s + 1) {
printf("s: %p\n", s);
}
}
void destroy(Container *t) {
free(t->firstmember);
t->firstmember = 0;
t->lastmember = 0;
}
int main(void) {
Container container;
Container *containerp = &container;
container.ndim = 1;
init(containerp);
process(containerp);
destroy(containerp);
container.ndim = 3;
init(containerp);
process(containerp);
destroy(containerp);
return 0;
}[/cpp]
On linux on x86_64, both ++s and s += 1 increase s by 8 independent of the value of t->ndim, whereas s = s + 1 increases s by sizeof(Member) == 8 + t->ndim * 8. Clearly the latter is intended. This was compiled icc Version 13.0.1.117 Build 20121010 by the way, without any further options - just icc foo.c && ./a.out.
I'm not entirely sure this code is legal; but I feel that either icc should refuse to compile it, or be consistent between the ways of incrementing s.
Thanks
Erik Postma
Maplesoft
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Not sure if I can edit my original post - I notice that the line continuation characters in the macro definition of TYPEDEFMEMBER do not show up. There should be a backslash at the end of four lines there - the definition ends with the line "} Member". Similarly but less crucially, there should be backslashes in the printf format strings. Sorry for the confusion.
Erik.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
What result do you get with the gcc compiler?
The compiler you are using is a bit old. The latest one that you could try is icc 13.1.1.163 Build 20130313.
--mark
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Mark,
Thanks for your response. gcc does the intended thing: it increases s by sizeof(Member) for each of the methods of increasing s.
Indeed, I have found out since yesterday that this is an undocumented (mis?)feature of gcc specifically; clang, for example, describes it at http://clang.llvm.org/docs/UsersManual.html#intentionally-unsupported-gcc-extensions as:
clang does not support the gcc extension that allows variable-length arrays in structures. This is for a few reasons: one, it is tricky to implement, two, the extension is completely undocumented, and three, the extension appears to be rarely used.
I guess this means that the obvious solution for you guys is to just refuse to compile it (which wouldn't solve the issue for me, but that's life I guess).
Erik.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page