is variant-length array declaration standard compatible?

B

bingfeng

Hi, everyone,
Is the following code

<CODE>
void foo(int n)
{
int a[n];
.....
}
</CODE>

standard compliant and portable?

I use intel's, M$'s, borland's Digital Mars's and GUN(c89)'s compiler
compiled it, the first three report error but the last two were passed
silently. I want to know whether that code is portable.

Ths in advance.


£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­
Best regards,
 
J

jacob navia

bingfeng said:
Hi, everyone,
Is the following code

<CODE>
void foo(int n)
{
int a[n];
.....
}
</CODE>

standard compliant and portable?

I use intel's, M$'s, borland's Digital Mars's and GUN(c89)'s compiler
compiled it, the first three report error but the last two were passed
silently. I want to know whether that code is portable.

Ths in advance.


£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­£­
Best regards,
This is defined in the C99 standard, and it is portable as long as you
use a C99 compiler.
To use it with gcc use the std=C99 option, if my memory doesn't betray
me.

jacob
 
R

Richard Bos

bingfeng said:
void foo(int n)
{
int a[n];
.....
}

standard compliant and portable?

I use intel's, M$'s, borland's Digital Mars's and GUN(c89)'s compiler
compiled it, the first three report error but the last two were passed
silently.

It's correct C99, not C89. It's a Ganuck extension to C89, IIRC; don't
know about Digital Mars. If you want to stay with C89, then no, it's not
portable.

Richard
 
C

CBFalconer

bingfeng said:
Is the following code

<CODE>
void foo(int n)
{
int a[n];
.....
}
</CODE>

standard compliant and portable?

I use intel's, M$'s, borland's Digital Mars's and GUN(c89)'s
compiler compiled it, the first three report error but the last
two were passed silently. I want to know whether that code is
portable.

At least in the GNU case you misused the compiler. It needs -ansi
-pedantic, and usefully also -W -Wall, to properly compile C.
Otherwise it compiles a mishmash of extensions.
 
K

Keith Thompson

CBFalconer said:
At least in the GNU case you misused the compiler. It needs -ansi
-pedantic, and usefully also -W -Wall, to properly compile C.
Otherwise it compiles a mishmash of extensions.

Or replace "-ansi" with "-std=c99" to compile a substantial subset of
C99.
 
M

Martin Ambuhl

bingfeng said:
Hi, everyone,
Is the following code

<CODE>
void foo(int n)
{
int a[n];
.....
}
</CODE>

standard compliant and portable?

No. '.....' is not a legal statement of any sort.
I use intel's, M$'s, borland's Digital Mars's and GUN(c89)'s compiler
compiled it,

I don't believe you.
 
R

Randy Howard

Or replace "-ansi" with "-std=c99" to compile a substantial subset of
C99.

Why bother? If you want portable C, you don't write anything containing
C99 extensions. Maybe that will change someday. In the meantime,
there isn't a lot you can't do with good old C89/90.
 
D

Denis Bueno

Randy Howard said:
Why bother? If you want portable C, you don't write anything containing
C99 extensions. Maybe that will change someday. In the meantime,
there isn't a lot you can't do with good old C89/90.

Since your claim involves some implicited definition of "a lot", I won't
claim to refute you. But, whatever the drawbacks, there are some very nifty
thing you /can/ do with C99 extensions, that you can't in C89.

In particular, you can do things like:

---------------------------------------------
#define WITH_MUTEX_LOCK(l) \
for (int WITH_MUTEX_LOCK_ret = (0 == pthread_mutex_lock(l)); \
WITH_MUTEX_LOCK_ret; \
WITH_MUTEX_LOCK_ret = 0, (void) pthread_mutex_unlock(l)) \

/* code ... */

void
foo (void) {
WITH_MUTEX_LOCK (lock) {
/* locked code */
}
}
---------------------------------------------

Or:

---------------------------------------------
#define WITH_OPEN_FILE(svar, file, mode) /* body */ \
for (void * svar = (void *) fopen(file, mode), * once_only = (void *) 1; \
once_only; \
fclose((FILE *) svar), once_only = (void *) 0)

void
foo (void) {
WITH_OPEN_FILE (stream, "/dev/random", "r") {
/* declarations */
fread(longdata, sizeof(long), 15, stream);
}
}
----------------------------------------------

These sorts of macros make (IMO) source code much more readable, mistakes
less likely (e.g. "Too many open files" if you're fopen()ing in a loop),
and mistake fixes more localized.

Code following this idiom can be multiplied ... but only because of the
ability to declare new variable within the initialize step of the for loop:
a C99 feature.

-Denis
 
J

Jean-Claude Arbaut

Le 13/06/2005 22:43, dans (e-mail address removed), « Denis Bueno »
These sorts of macros make (IMO) source code much more readable, mistakes
less likely (e.g. "Too many open files" if you're fopen()ing in a loop),
and mistake fixes more localized.

Code following this idiom can be multiplied ... but only because of the
ability to declare new variable within the initialize step of the for loop:
a C99 feature.

-Denis

What about this ?

#define WITH_MUTEX_LOCK(l) \
int WITH_MUTEX_LOCK_ret; \
for (WITH_MUTEX_LOCK_ret = (0 == pthread_mutex_lock(l)); \
WITH_MUTEX_LOCK_ret; \
WITH_MUTEX_LOCK_ret = 0, (void) pthread_mutex_unlock(l))

void foo(void) {
{
WITH_MUTEX_LOCK(lock) {
/* locked code */
}
}
}

It seems only slighlty less readable...
 
D

Denis Bueno

Jean-Claude Arbaut said:
#define WITH_MUTEX_LOCK(l) \
int WITH_MUTEX_LOCK_ret; \
for (WITH_MUTEX_LOCK_ret = (0 == pthread_mutex_lock(l)); \
WITH_MUTEX_LOCK_ret; \
WITH_MUTEX_LOCK_ret = 0, (void) pthread_mutex_unlock(l))

void foo(void) {
{
WITH_MUTEX_LOCK(lock) {
/* locked code */
}
}
}

It seems only slighlty less readable...

Consider, with your definition of WITH_MUTEX_LOCK:

WITH_MUTEX_LOCK (mutex) {
// stuff
}
// stuff
WITH_MUTEX_LOCK (mutex) {
// stuff
}

That code, if I'm not mistaken, will give you a compile error. You need an
independent scope for the macro expansions.

Also, if for any reason you (accidentally) refer to WITH_MUTEX_LOCK_ret
(typo, or whatever) outside of the WITH_MUTEX_LOCK (l) { ... } block, you
will capture whatever garbage is in the variable declared by the
macro. This behavior /completely/ violates the semantics of the block
structure.

Although with my version the code inside the block can capture the
WITH_MUTEX_LOCK_ret variable (which is because there is no way to generate
unique variable names automatically in C), it doesn't violate the semantics
of the block structure, and it doesn't cause the compiler to barf if the
macro is used twice in the same scope.

-Denis
Remove dvorak-noise from From.
 
J

Jean-Claude Arbaut

Le 17/06/2005 03:29, dans (e-mail address removed), « Denis Bueno »
Consider, with your definition of WITH_MUTEX_LOCK:

WITH_MUTEX_LOCK (mutex) {
// stuff
}
// stuff
WITH_MUTEX_LOCK (mutex) {
// stuff
}

That code, if I'm not mistaken, will give you a compile error. You need an
independent scope for the macro expansions.

That's why I put curly braces around !
Also, if for any reason you (accidentally) refer to WITH_MUTEX_LOCK_ret
(typo, or whatever) outside of the WITH_MUTEX_LOCK (l) { ... } block, you
will capture whatever garbage is in the variable declared by the
macro.

It simply should never happen. It suffices to remember the outer {...} block
can only contain one macro expansion and nothing else. I use it merely to
be able to declare a local variable with a name common to all macros.
This behavior /completely/ violates the semantics of the block
structure.

I'm not sure, but I'm not sure you are wrong either :)
Although with my version the code inside the block can capture the
WITH_MUTEX_LOCK_ret variable (which is because there is no way to generate
unique variable names automatically in C), it doesn't violate the semantics
of the block structure, and it doesn't cause the compiler to barf if the
macro is used twice in the same scope.

I was just trying to show you C99 is not absolutely needed for that trick.
 
M

Me

#define WITH_OPEN_FILE(svar, file, mode) /* body */ \
for (void * svar = (void *) fopen(file, mode), * once_only = (void *) 1; \
once_only; \
fclose((FILE *) svar), once_only = (void *) 0)

void
foo (void) {
WITH_OPEN_FILE (stream, "/dev/random", "r") {
/* declarations */
fread(longdata, sizeof(long), 15, stream);
}
}
<snip>

Change once_only's initializer to &svar (and get rid of all the (void*)
casting), otherwise it's not guaranteed what (void*)1 will return when
being evaluated for a truth value. Infact, I'd probably rewrite it as
the following since the above doesn't handle fopen failing:

#define WITH_OPEN_FILE(svar, file, mode) \
for (FILE *svar = fopen(file, mode); svar; fclose(svar), svar = 0)

In C++, this would be much better because it allows initializers in
conditionals. That feature combined with destructors lets you could do:

if (file_t file = create_file(name, mode)) {
// read file
} else {
// handle failure
}

And not let the break/return statement accidentally leak a filehandle.
But, I'm already off-topic for this newsgroup.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top