Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Q: Local variables initialization shortcut.

46 views
Skip to first unread message

Jean-Christophe

unread,
Jun 2, 2012, 5:49:23 AM6/2/12
to
Hi all,

The function f() has some local (double)
which should all be initialized to zero :

a = b = c = ... = y = z = 0.0;

Can I use a shortcut like this :

memset( &a, 0, number_of_variables * sizeof(double) );

If yes, can I do this :

memset( &a, 0, (&z - &a + sizeof(double)) );

Like this :

void f(void)
{
double a,b,c,d,...,x,y,z;

memset( &a, 0, (unsigned int)( &z - &a + sizeof(double) ) );

...
}

--------

PS :
Of course the # of variables is not always 26,
that's why I want an easy way to implement initialization to zero.

Message has been deleted

jacob navia

unread,
Jun 2, 2012, 6:06:13 AM6/2/12
to
Le 02/06/12 11:49, Jean-Christophe a écrit :
> Hi all,
>
> The function f() has some local (double)
> which should all be initialized to zero :
>
> a = b = c = ... = y = z = 0.0;
>
> Can I use a shortcut like this :
>
> memset(&a, 0, number_of_variables * sizeof(double) );
>
> If yes, can I do this :
>
> memset(&a, 0, (&z -&a + sizeof(double)) );
>
> Like this :
>
> void f(void)
> {
> double a,b,c,d,...,x,y,z;
>
> memset(&a, 0, (unsigned int)(&z -&a + sizeof(double) ) );
>
> ...
> }
>
> --------
>
> PS :
> Of course the # of variables is not always 26,
> that's why I want an easy way to implement initialization to zero.
>

No, in general you can't. The compiler may align the double variables at
a 16 byte boundary for instance, for performance reasons. That would
mean that the compiler would leave 8 bytes unused between each variable.

Another problem could be that the compiler doesn't store those variables
in a contiguos fashion but interleaves variables with other data (maybe
because alignment reasons)

An easy solution to your problem is:

#include <stdio.h>
int main(void) {
int i;

for (i='a'; i<= 'z'; i++) {
printf("\t%c = 0.0;\n",i);
}
}

Redirect the output to a file and insert that file
into your source code

:-)

Ian Collins

unread,
Jun 2, 2012, 6:10:18 AM6/2/12
to
On 06/ 2/12 09:49 PM, Jean-Christophe wrote:
> Hi all,
>
> The function f() has some local (double)
> which should all be initialized to zero :
>
> a = b = c = ... = y = z = 0.0;
>
> Can I use a shortcut like this :
>
> memset(&a, 0, number_of_variables * sizeof(double) );
>
> If yes, can I do this :
>
> memset(&a, 0, (&z -&a + sizeof(double)) );
>
> Like this :
>
> void f(void)
> {
> double a,b,c,d,...,x,y,z;
>
> memset(&a, 0, (unsigned int)(&z -&a + sizeof(double) ) );
>
> ...
> }
>
> --------
>
> PS :
> Of course the # of variables is not always 26,
> that's why I want an easy way to implement initialization to zero.

If they need to be initialised, declare and initialise them when they
are first used.

--
Ian Collins

Jean-Christophe

unread,
Jun 2, 2012, 6:17:21 AM6/2/12
to
On 2 juin, 12:03, China Blue Max :

| Jean-Christophe :
| Can I use a shortcut like this (...)

> No.
> You cannot assume anything about assignment of variables to memory.

*sigh* ... okay, thanks !

Jean-Christophe

unread,
Jun 2, 2012, 6:25:01 AM6/2/12
to
On 2 juin, 12:06, jacob navia :

| Can I use a shortcut like this (...)

> No, in general you can't. The compiler may align the double variables at
> a 16 byte boundary for instance, for performance reasons. That would
> mean that the compiler would leave 8 bytes unused between each variable.
> Another problem could be that the compiler doesn't store those variables
> in a contiguos fashion but interleaves variables with other data (maybe
> because alignment reasons)

Okay, thanks.

Since these variables are located in the stack,
is there a way to FORCE the compiler to align them,
using a compiler directive or something ?


> An easy solution to your problem is:
> #include <stdio.h>
> int main(void) {
> int i;
> for (i='a'; i<= 'z'; i++) {
> printf("\t%c = 0.0;\n",i);
> }
> }
> Redirect the output to a file and insert
> that file into your source code :-)

That's not what I call 'easy'.

Jens Thoms Toerring

unread,
Jun 2, 2012, 6:31:13 AM6/2/12
to
Jean-Christophe <5...@free.fr> wrote:
> The function f() has some local (double)
> which should all be initialized to zero :

> double a,b,c,d,...,x,y,z;
> a = b = c = ... = y = z = 0.0;

> Can I use a shortcut like this :

> memset( &a, 0, number_of_variables * sizeof(double) );

Your idea has a number of problems: for once, while it is
not unlikely that they are all in consecutive memory lo-
cations, that's not guaranteed - the simplest practical
reason would be that the compiler finds that one or more
of the variables is not really needs to be kept in memory
and can be optimized to reside in a CPU register only. Se-
cond, even if that wouldn't be an issue, there is no reason
at all that 'a' should be at the lowest address - quite
often the variable defined last is the one with the lowest
address - this is completely at the discretion of the com-
piler. Finally not on all systems a 0.0 value is represen-
ted by all bits set to zero.

> If yes, can I do this :

> memset( &a, 0, (&z - &a + sizeof(double)) );

'&z - &a' isn't legal - you can only subtract addresses
of locations within a single object (e.g. an array),
everything else is undefined behaviour, And even if
disregarding this and assuming that 'a' is at the lowest
and 'z' at the highest address, '&z - &a' will be the
number of variable between 'a' and 'z' (25) and not the
number of bytes used in between, so you would have to
multiply by the size of a double.

Since you try to treat these variables (at least in the
respect of initialization) as if they make up an array,
would it be possible to atually use an array? Then ini-
tialization is rather simple:

double a2z[ 26 ] = { 0.0 };

Regards, Jens
--
\ Jens Thoms Toerring ___ j...@toerring.de
\__________________________ http://toerring.de

BartC

unread,
Jun 2, 2012, 6:45:45 AM6/2/12
to
"Jean-Christophe" <5...@free.fr> wrote in message
news:5835baa1-db3f-4b81...@w24g2000vby.googlegroups.com...

> The function f() has some local (double)
> which should all be initialized to zero :
>
> a = b = c = ... = y = z = 0.0;
>
> Can I use a shortcut like this :
>
> memset( &a, 0, number_of_variables * sizeof(double) );
>
> If yes, can I do this :
>
> memset( &a, 0, (&z - &a + sizeof(double)) );
>
> Like this :
>
> void f(void)
> {
> double a,b,c,d,...,x,y,z;
>
> memset( &a, 0, (unsigned int)( &z - &a + sizeof(double) ) );
>
> ...
> }

You need a feature not available in C, which is being able to have a
variable which is an alias of another. It might work like this:

double V[26]={0};
double a @ V[0], b @ V[1], etc.

Then identifier 'c' is equivalant to 'V[2]'. This way you might expect the
26-element V array to be cleared more efficiently than 26 individual
variables.

The nearest C can actually do might be:

#define a (V[0])
#define b (V[1])
etc

But, these macro names will have file scope; they will no longer be local.
(Unless maybe you play around with #undef and stuff like that.) Of course
your actual variable names might not be single letters so it need not be an
issue.

You can also use array elements directly: V[0], V[1] in place of a,b. Or
define some enumerations:

enum {a,b,c...} so that it's possible to write V[a], V[b] etc.

Alternatively, a struct can be used to contain all the variables:

struct {double a, b, c,... }V = {0};

Now you can just write: V.a, V.b and so on.

It's possible also that your compiler will arrange the variables so that it
can initialise them as one block anyway...

--
bartc

Jean-Christophe

unread,
Jun 2, 2012, 6:59:01 AM6/2/12
to
On 2 juin, 12:31, j...@toerring.de :

> Your idea has a number of problems: for once, while it is
> not unlikely that they are all in consecutive memory lo-
> cations, that's not guaranteed - the simplest practical
> reason would be that the compiler finds that one or more
> of the variables is not really needs to be kept in memory
> and can be optimized to reside in a CPU register only. Se-
> cond, even if that wouldn't be an issue, there is no reason
> at all that 'a' should be at the lowest address - quite
> often the variable defined last is the one with the lowest
> address - this is completely at the discretion of the com-
> piler.

Okay.


> Finally not on all systems a 0.0 value
> is represented by all bits set to zero.

Well, at least this is the case for
Windows float and double, isn't it ?


> '&z - &a' isn't legal - you can only subtract addresses
> of locations within a single object (e.g. an array),

I've done it many times and it always worked fine :
&a is the address of 'a' so it's its memory location.
Except for this actual example (when variables are stored
in stack w/ their adresses allocated by the compiler)
if the location of 'a' thru 'z' are well stored
(i.e, like in an array) then the following code works fine :
unsigned int size = (unsigned int)( &z - &a );


> everything else is undefined behaviour, And even if
> disregarding this and assuming that 'a' is at the lowest
> and 'z' at the highest address, '&z - &a' will be the
> number of variable between 'a' and 'z' (25) and not the
> number of bytes used in between, so you would have to
> multiply by the size of a double.

Hum, no : if &z is the highest address
and &a is the lowest address then (&z - &a)
is the number of bytes (less one sizeof) and not the
number of variables (unless 'a' and 'z' are chars)


> Since you try to treat these variables (at least in the
> respect of initialization) as if they make up an array,
> would it be possible to atually use an array? Then ini-
> tialization is rather simple:
> double a2z[ 26 ] = { 0.0 };

Yes of course, but the problem is that these
variables names are not as simple as 'a'...'z'
and they are used individually (am I clear here ?)
So then, to use your suggestion I should do something like

// declare & init

#define VAR_THIS d[0]
#define VAR_THAT d[1]
#define VAR_SOMETHING d[2]
... etc ...
#define VAR_MAX 10 // for instance

double d[VAR_MAX];
memset( d, 0, VAR_MAX * sizeof(d[0]) );

// using variables

VAR_THIS = ... ;
VAR_THAT = ... ;
x = ... VAR_THIS ... VAR_THAT ... ;

... but then, to write the whole set
of #define looks a bit heavy to me !

Thanks, Jens.

Jean-Christophe

unread,
Jun 2, 2012, 7:17:11 AM6/2/12
to
On 2 juin, 12:45, "BartC" :

> You need a feature not available in C, which is being able to have a
> variable which is an alias of another. It might work like this:
> double V[26]={0};
> double a @ V[0], b @ V[1], etc.
> Then identifier 'c' is equivalant to 'V[2]'. This way you might expect the
> 26-element V array to be cleared more efficiently than 26 individual
> variables.

Yep.


> The nearest C can actually do might be:
> #define a (V[0])
> #define b (V[1])
> etc

Yes, that's what I said to 'Jens'.
But to write the whole set of #define will be a pain.
( some functions have as much as ~50 variables ... )


> But, these macro names will have file scope; they will no longer be local.
> (Unless maybe you play around with #undef and stuff like that.)

Yes, in this case that's what I would have done.
( just at the end '}' of the function)


> Of course your actual variable names might not be single letters

No, they are not single letters.


> so it need not be an issue.
> You can also use array elements directly: V[0], V[1] in place of a,b. Or
> define some enumerations:
> enum {a,b,c...} so that it's possible to write V[a], V[b] etc.

Yes, but then, using variables in the code will look like :

V[VAR_THIS] = ... ;

Which I found less easy-to-use and trensparent than :

VAR_THIS = ... ;


> Alternatively, a struct can be used to contain all the variables:
> struct {double a, b, c,... }V = {0};
> Now you can just write: V.a, V.b and so on.

Yes, I think it's the easyest shortcut in this case.

Now the drawback is : many functions with always-different
variable names, meaning a lot of different structures to define.


> It's possible also that your compiler will arrange the variables
> so that it can initialise them as one block anyway...

Yes, but I can't seriously rely on this since these
are local allocations in stack, done at runtime, etc.

I'm translating an existing source code into C language so
I'm using the very same variables names (to ease debugging)
I *have* to keep separate, 'individual', variables names.
(if I wrote it down in the fist place, I'd use structures)

BartC

unread,
Jun 2, 2012, 7:40:15 AM6/2/12
to


"Jean-Christophe" <5...@free.fr> wrote in message
news:e51b172a-e540-4893...@m24g2000yqh.googlegroups.com...
> On 2 juin, 12:45, "BartC" :
>
>> You need a feature not available in C, which is being able to have a
>> variable which is an alias of another. It might work like this:
>> double V[26]={0};
>> double a @ V[0], b @ V[1], etc.
>> Then identifier 'c' is equivalant to 'V[2]'. This way you might expect
>> the
>> 26-element V array to be cleared more efficiently than 26 individual
>> variables.
>
> Yep.

Actually, if you are using doubles, then it doesn't necessarily follow that
it will be much slower to clear these one-by-one, compared with, say, 8 or
16-bit variables. (It's possible also it might be faster, if the compiler
would otherwise use a loop.) Have you done any measurements?

> I'm translating an existing source code into C language so
> I'm using the very same variables names (to ease debugging)
> I *have* to keep separate, 'individual', variables names.
> (if I wrote it down in the fist place, I'd use structures)

Do the variables need to be cleared on every call to the function? If they
only need to be cleared once, then using static variables will ensure they
are 0.0 at the start of execution (at least, on most hardware).

Also, does *every* variable need to start at zero? Some, surely, must have a
different starting value, perhaps set by an assignment. (In which case, a
compiler might optimise out the 0.0 initialisation; but it means you don't
need to clear it first.)

You mentioned Windows elsewhere. If you're only interested in one particular
platform (eg. x86) and don't care about portability, perhaps consider a bit
of inline assembler. This can look at the frame and stack pointers, and do a
block clear of the memory in between. Although this will indiscriminately
zero all local variables, including ones you want initialised to something
else. (They need initialising by assignment instead.)

--
Bartc

BartC

unread,
Jun 2, 2012, 7:51:59 AM6/2/12
to
"BartC" <b...@freeuk.com> wrote in message news:jqcu41$oa0$1...@dont-email.me...
> "Jean-Christophe" <5...@free.fr> wrote in message

>> I'm translating an existing source code into C language so

> You mentioned Windows elsewhere. If you're only interested in one
> particular
> platform (eg. x86) and don't care about portability, perhaps consider a
> bit
> of inline assembler. This can look at the frame and stack pointers, and do
> a block clear of the memory in between.

I should add this might not be portable across compilers either. Especially
gcc, which might just decide to eliminate the frame pointer completely. But
then it also makes it more difficult to use inline asm anyway.

--
Bartc

Jens Thoms Toerring

unread,
Jun 2, 2012, 7:55:53 AM6/2/12
to
Jean-Christophe <5...@free.fr> wrote:
> On 2 juin, 12:31, j...@toerring.de :
> > Finally not on all systems a 0.0 value
> > is represented by all bits set to zero.

> Well, at least this is the case for
> Windows float and double, isn't it ?

Probably, since all hardware on Windows seem to be using
the very common IEEE 754 format for floating points. But
that isn't something required by the C standard, some sys-
tems may use a different bit representation for floating
points.

> > '&z - &a' isn't legal - you can only subtract addresses
> > of locations within a single object (e.g. an array),

> I've done it many times and it always worked fine :
> &a is the address of 'a' so it's its memory location.

Well, you were lucky. The standard doesn't define what
the result of subtracting pointers not within the same
object is (or, in the case of arrays, one beyond the
end of the array), so you are relying on whatever your
compiler makes out of it. Some other compiler might
give you a different result.

> Except for this actual example (when variables are stored
> in stack w/ their adresses allocated by the compiler)

There also is no requirement for a stack in the C stan-
dard. Most (or probably all) compilers will employ
something stack-like for local variables, but that is
a decision the compiler writer makes, not something
prescribed by the standard.

> if the location of 'a' thru 'z' are well stored
> (i.e, like in an array) then the following code works fine :
> unsigned int size = (unsigned int)( &z - &a );

Yes, it may seem to work on your system with the specific
compiler you are using. If you want your program to work
only on that system and with that compiler then this is
probably all fine, just dont expect it to work anymore
under different circumstances.

> > everything else is undefined behaviour, And even if
> > disregarding this and assuming that 'a' is at the lowest
> > and 'z' at the highest address, '&z - &a' will be the
> > number of variable between 'a' and 'z' (25) and not the
> > number of bytes used in between, so you would have to
> > multiply by the size of a double.

> Hum, no : if &z is the highest address
> and &a is the lowest address then (&z - &a)
> is the number of bytes (less one sizeof) and not the
> number of variables (unless 'a' and 'z' are chars)

That may well be the case. Since you are relying on un-
defined behaviour everything you get is "right". Just for
the fun of it: on my system (x86-64 Linux and with gcc)
the output of this program

#include <stdio.h>
int main( void )
{
double a, b;
printf( "%d\n", ( int ) ( &a - &b ) );
return 0;
}

is -1. So obviously at least some of the deductions you
were led to make by the behaviour on your system aren't
valid from what I see on my machine. And that's quite
ok since the behaviour of that program isn't defined,
so whatever the output is is correct. (And I have de-
finitely worked with machines were variables defined
later had lower addresses).

For even more giggles take this program:

#include <stdio.h>
int main( void )
{
double a, b, c;
printf( "%d\n", ( int ) ( &a - &c ) );
return 0;
}

The output on my machine is still -1...

But I am a bit puzzled - I would expect the difference
between two pointers of the same type to be number of
variables of that type in between, not the number of
bytes. Otherwise the behaviour (while undefined) would
be even more weird on your machine since e.g. for
arrays you can rely on the difference between the
addresses of two of its elements to be the number of
elements in between. But then, again, the moment you
do something undefined everything can happen.

> > Since you try to treat these variables (at least in the
> > respect of initialization) as if they make up an array,
> > would it be possible to atually use an array? Then ini-
> > tialization is rather simple:
> > double a2z[ 26 ] = { 0.0 };

> Yes of course, but the problem is that these
> variables names are not as simple as 'a'...'z'
> and they are used individually (am I clear here ?)
> So then, to use your suggestion I should do something like

> // declare & init

> #define VAR_THIS d[0]
> #define VAR_THAT d[1]
> #define VAR_SOMETHING d[2]
> ... etc ...
> #define VAR_MAX 10 // for instance

> double d[VAR_MAX];
> memset( d, 0, VAR_MAX * sizeof(d[0]) );

> // using variables

> VAR_THIS = ... ;
> VAR_THAT = ... ;
> x = ... VAR_THIS ... VAR_THAT ... ;

> ... but then, to write the whole set
> of #define looks a bit heavy to me !

Of course, this is the probably even worse than
writing

a = b = c = .... = z = 0.0;

since it's much harder to understand. The only conclusion
is that what you want to do can't be done in a portable
fashion in C.
Refards, Jens

Jean-Christophe

unread,
Jun 2, 2012, 7:57:23 AM6/2/12
to
On 2 juin, 13:40, "BartC" :

> Actually, if you are using doubles, then it doesn't necessarily follow that
> it will be much slower to clear these one-by-one, compared with, say, 8 or
> 16-bit variables. (It's possible also it might be faster, if the compiler
> would otherwise use a loop.) Have you done any measurements?

The speed is not an issue here.
The point is to reset to zero all these variables,
while keeping their original names.


> Do the variables need to be cleared on every call to the function?

Yes.


> If they only need to be cleared once, then using static variables
> will ensure they are 0.0 at the start of execution
> (at least, on most hardware).

Nah, can't be static.


> Also, does *every* variable need to start at zero?
> Some, surely, must have a different starting value,
> perhaps set by an assignment.

Yes.


> (In which case, a compiler might optimise out the 0.0
> initialisation; but it means you don't need to clear it first.)

That's right, but the original code is a real mess,
for debug purpose I need al least to set all variables to zero
otherwise I won't even know whose values are (in)correct.


> You mentioned Windows elsewhere. If you're only interested in one particular
> platform (eg. x86) and don't care about portability,

Yes, this is the case.


> perhaps consider a bit of inline assembler.
> This can look at the frame and stack pointers, and do a
> block clear of the memory in between. Although this will indiscriminately
> zero all local variables, including ones you want initialised to something
> else. (They need initialising by assignment instead.)

Hum, sounds a bit tricky to me.
Thanks for the idea anyway.

pete

unread,
Jun 2, 2012, 8:03:52 AM6/2/12
to
Jean-Christophe wrote:
>
> On 2 juin, 12:31, j...@toerring.de :

> > '&z - &a' isn't legal - you can only subtract addresses
> > of locations within a single object (e.g. an array),
>
> I've done it many times and it always worked fine :

If you beieve that something which works once,
will always work again,
then why ask questions
instead of just testing your code?

> &a is the address of 'a' so it's its memory location.

The C standard characterizes that operation as being undefined.

N1570
6.5.6 Additive operators

9 When two pointers are subtracted,
both shall point to elements of the same array object,
or one past the last element of the array object;
the result is the difference of the
subscripts of the two array elements.

--
pete

pete

unread,
Jun 2, 2012, 8:15:14 AM6/2/12
to
Jens Thoms Toerring wrote:
>
> Jean-Christophe <5...@free.fr> wrote:
> > On 2 juin, 12:31, j...@toerring.de :

On the machine that I am using,
the following program outputs a pair of 1's.

#include <stdio.h>

int
main( void )
{
{
double a, b;
printf( "%d\n", ( int ) ( &a - &b ) );
}
{
double b, a;
printf( "%d\n", ( int ) ( &a - &b ) );
}
return 0;
}

--
pete

Jean-Christophe

unread,
Jun 2, 2012, 8:18:13 AM6/2/12
to
On 2 juin, 14:03, pete :

> If you beieve that something which works once,
> will always work again,

I didn't meant that.

> then why ask questions
> instead of just testing your code?

Because I need advice.

> The C standard characterizes that operation as being undefined.
> N1570
> 6.5.6 Additive operators
> 9 When two pointers are subtracted,
> both shall point to elements of the same array object,
> or one past the last element of the array object;
> the result is the difference of the
> subscripts of the two array elements.

Good enough for me, thanks.

Jean-Christophe

unread,
Jun 2, 2012, 8:37:24 AM6/2/12
to
On 2 juin, 13:55, j...@toerring.de (Jens Thoms Toerring) wrote:

> > > Finally not on all systems a 0.0 value
> > > is represented by all bits set to zero.
> > Well, at least this is the case for
> > Windows float and double, isn't it ?
> Probably, since all hardware on Windows seem to be using
> the very common IEEE 754 format for floating points. But
> that isn't something required by the C standard, some sys-
> tems may use a different bit representation for floating
> points.

Ok.


> > > '&z - &a' isn't legal - you can only subtract addresses
> > > of locations within a single object (e.g. an array),
> > I've done it many times and it always worked fine :
> > &a is the address of 'a' so it's its memory location.
> Well, you were lucky. The standard doesn't define what
> the result of subtracting pointers not within the same
> object is (or, in the case of arrays, one beyond the
> end of the array), so you are relying on whatever your
> compiler makes out of it. Some other compiler might
> give you a different result.

Ok, I'll remember that.


> > Except for this actual example (when variables are stored
> > in stack w/ their adresses allocated by the compiler)
> There also is no requirement for a stack in the C stan-
> dard. Most (or probably all) compilers will employ
> something stack-like for local variables, but that is
> a decision the compiler writer makes, not something
> prescribed by the standard.

Ok.


> > if the location of 'a' thru 'z' are well stored
> > (i.e, like in an array) then the following code works fine :
> > unsigned int size = (unsigned int)( &z - &a );
> Yes, it may seem to work on your system with the specific
> compiler you are using. If you want your program to work
> only on that system and with that compiler then this is
> probably all fine, just dont expect it to work anymore
> under different circumstances.

Right. This is clumsy.
You are right because you're talking about *pointers* :
int i;
double d1, d2, *a, *b;
a = &d1;
b = &d2;
i = (int)( b - a ); // assuming &d2 > &d1
then i == 1 // number of variables
because it's a difference of pointers
of a given variable type.

This is a different matter than :
int i;
double d1, d2;
i = (int)( &d2 - &d1 ); // assuming &d2 > &d1
then i == sizeof(double) // number of bytes
because it's a difference of addresses
whatever the variable type is.


> > ... but then, to write the whole set
> > of #define looks a bit heavy to me !
> Of course, this is the probably even worse than writing
> a = b = c = .... = z = 0.0;
> since it's much harder to understand. The only conclusion
> is that what you want to do can't be done in a portable
> fashion in C.

All right then.
I understand I made the error of expanding my knowledge
of 'micro-controllers' C compilers to the 'PC' C compilers.
Some things won't work at all, and if they do
it's even worse because it's just luck.

Thanks for taking time.

Eric Sosman

unread,
Jun 2, 2012, 8:46:23 AM6/2/12
to
On 6/2/2012 7:55 AM, Jens Thoms Toerring wrote:
> Jean-Christophe<5...@free.fr> wrote:
>> [...]
>>> '&z -&a' isn't legal - you can only subtract addresses
>>> of locations within a single object (e.g. an array),
>
>> I've done it many times and it always worked fine :
>> &a is the address of 'a' so it's its memory location.
>
> Well, you were lucky. The standard doesn't define what
> the result of subtracting pointers not within the same
> object is (or, in the case of arrays, one beyond the
> end of the array), so you are relying on whatever your
> compiler makes out of it. Some other compiler might
> give you a different result.

As a concrete example not requiring "exotic" hardware,
consider this fragment:

char buff[15];
typedef char Blob[7];
Blob *b1 = (Blob*) &buff[0];
Blob* b2 = (Blob*) &buff[8];

Now, what is `b2 - b1'? Pointer subtraction is supposed to
yield the number of pointed-at things between the two positions,
but how many 7-byte Blobs fit in the 8 bytes between their
starting positions? (For extra credit, change `8' to `1' in
the final line and answer again.)

In other words, the requirement is even stronger than Jens'
informal statement of it: You can only subtract pointers within
an array *of the pointed-at type*. The fact that `b1' and `b2'
both aim at spots within the array `buff' is not enough.

--
Eric Sosman
eso...@ieee-dot-org.invalid

Jean-Christophe

unread,
Jun 2, 2012, 8:46:38 AM6/2/12
to
My apologies :

#include <stdio.h>
int main(void)
{
double a,b;
printf( "&b - &a = %2d\r\n", (int)( &b - &a ) );
printf( "&a - &b = %2d\r\n", (int)( &a - &b ) );
return 0;
}

&b - &a = 1
&a - &b = -1

Jean-Christophe

unread,
Jun 2, 2012, 8:53:27 AM6/2/12
to
Sorry about the misunderstanding,
this is what I meant :

#include <stdio.h>
double a,b;
int main(void)
{
unsigned int ia = (unsigned int)&a;
unsigned int ib = (unsigned int)&b;
printf( "ib - ia = %u\r\n", ib - ia );
printf( "ia - ib = %u\r\n", ia - ib );
return 0;
}


ib - ia = 8 // = sizeof(double)
ia - ib = 4294967288 // crap

BartC

unread,
Jun 2, 2012, 9:00:42 AM6/2/12
to
"Jean-Christophe" <5...@free.fr> wrote in message
news:4b5d8284-87f0-4596...@j9g2000vbk.googlegroups.com...
> On 2 juin, 13:40, "BartC" :
>
>> Actually, if you are using doubles, then it doesn't necessarily follow
>> that
>> it will be much slower to clear these one-by-one, compared with, say, 8
>> or
>> 16-bit variables. (It's possible also it might be faster, if the compiler
>> would otherwise use a loop.) Have you done any measurements?
>
> The speed is not an issue here.
> The point is to reset to zero all these variables,
> while keeping their original names.

Perhaps I'm missing the point somewhere, but in that case, what's wrong
with:

double a=0.0, b=0.0, .... ?

Do you just want to save some typing?

> perhaps consider a bit of inline assembler.
>> This can look at the frame and stack pointers, and do a
>> block clear of the memory in between.

> Hum, sounds a bit tricky to me.
> Thanks for the idea anyway.

Yeah, forget that. You need to be on intimate terms with your compiler to
try things like that.

--
Bartc



Jean-Christophe

unread,
Jun 2, 2012, 9:12:27 AM6/2/12
to
On 2 juin, 15:00, "BartC" :

> Perhaps I'm missing the point somewhere,
> but in that case, what's wrong with:
> double a=0.0, b=0.0, .... ?
> Do you just want to save some typing?

I'm re-writing a messy 7500 lines source code into C,
I kept all the same variables names to ease debugging
and there are a LOT of functions, each one with its
own LOT of local variables - all having different names.
At least I want to initialise all of them to zero to
avoid uninitialized variables fuck-up (if I may say so)

So it won't save me 'some' typing: I'll save a 'lot' of typing.


> > perhaps consider a bit of inline assembler.
> >> This can look at the frame and stack pointers, and do a
> >> block clear of the memory in between.
> > Hum, sounds a bit tricky to me.
> > Thanks for the idea anyway.

> Yeah, forget that. You need to be on intimate
> terms with your compiler to try things like that.

Sure. Thanks Bartc.

Jens Thoms Toerring

unread,
Jun 2, 2012, 9:35:55 AM6/2/12
to
Jean-Christophe <5...@free.fr> wrote:
> On 2 juin, 13:55, j...@toerring.de (Jens Thoms Toerring) wrote:
> You are right because you're talking about *pointers* :
> int i;
> double d1, d2, *a, *b;
> a = &d1;
> b = &d2;
> i = (int)( b - a ); // assuming &d2 > &d1
> then i == 1 // number of variables
> because it's a difference of pointers
> of a given variable type.

> This is a different matter than :
> int i;
> double d1, d2;
> i = (int)( &d2 - &d1 ); // assuming &d2 > &d1
> then i == sizeof(double) // number of bytes
> because it's a difference of addresses
> whatever the variable type is.

I don't agree - you are subtracting adresses and, as
long as you don't cross the border of undefined beha-
viour, it doesn't matter if you directly subtract the
addresses of two variables or first store those addres-
ses in pointers and then subtract their values. All what
(at least when used as defined by the standard, i.e.
when subtracting the addresses of elements of an array)
is the type of the elements. Thus

double a[ 10 ];
double * ap2 = &a[ 2 ],
* ap7 = &a[ 7 ];
printf( "%d %d\n", ( int ) ( &a[ 7 ] - &a[ 2 ] ),
( int ) ( ap7 - ap2 ) );

will always output "5 5", the number of elements in
between (and you're guaranteed that later elements in
the array have higher addresses). If you want the
number of bytes then you have to either multiply by
the size of a double or cast the addresses of the
array elements to char before subtracting them.

When instead of doing that on elements of an array
on addresses of unrelated objects then the results
could actually be different, but there's nothing which
would tell you which one is correct or to be expected -
the compiler writer can pick whatever behaviour (s)he
considers appropriate. It would also be "correct" when
the result would always be 42.

> I understand I made the error of expanding my knowledge
> of 'micro-controllers' C compilers to the 'PC' C compilers.
> Some things won't work at all, and if they do
> it's even worse because it's just luck.

You may indeed have gotten used to a "dialect" of C (or
certain ways those compilers handle things not defined
by the standard) and you may have to unlearn a few things
you are taking for granted. Bin there, done that and
sweared quite a bit along the way;-) And it's sometimes
quite hard to grasp why certain constructs aren't well
defined by the standard, especially when one comes from
an assembler background and for quite a number of things
there is an "obvious" way in which one would assumes they
should be dealt with. There's a long list of things that
are either unspecified, undefined or implementation defined
at the end of the C99 standard (Annex J). It's not an easy
read but can help a bit getting an idea what one should
avoid when trying to write portable programs.

Regards, Jens

Jean-Christophe

unread,
Jun 2, 2012, 9:47:31 AM6/2/12
to
On 2 juin, 15:35, j...@toerring.de (Jens Thoms Toerring) wrote:

> > int i;
> > double d1, d2;
> > i = (int)( &d2 - &d1 ); // assuming &d2 > &d1
> > then i == sizeof(double) // number of bytes
> > because it's a difference of addresses
> > whatever the variable type is.

> I don't agree (...)

Yes, sorry about that.
What I had in mind was this :

#include <stdio.h>
double a,b;
int main(void)
{
unsigned int ia = (unsigned int)&a;
unsigned int ib = (unsigned int)&b;
printf( "ib - ia = %u\r\n", ib - ia );
printf( "ia - ib = %u\r\n", ia - ib );
return 0;
}

Output :
ib - ia = 8 // = sizeof(double)
ia - ib = 4294967288 // 0xFFFFFFF8


> When instead of doing that on elements of an array
> on addresses of unrelated objects then the results
> could actually be different, but there's nothing which
> would tell you which one is correct or to be expected -
> the compiler writer can pick whatever behaviour (s)he
> considers appropriate. It would also be "correct" when
> the result would always be 42.

I got that !
(Douglas Noel Adams, uh ?)


> You may indeed have gotten used to a "dialect" of C (or
> certain ways those compilers handle things not defined
> by the standard) and you may have to unlearn a few things
> you are taking for granted. Bin there, done that and
> sweared quite a bit along the way;-) And it's sometimes
> quite hard to grasp why certain constructs aren't well
> defined by the standard, especially when one comes from
> an assembler background

That's it : I'm an electronician.


> and for quite a number of things
> there is an "obvious" way in which one would assumes they
> should be dealt with. There's a long list of things that
> are either unspecified, undefined or implementation defined
> at the end of the C99 standard (Annex J). It's not an easy
> read but can help a bit getting an idea what one should
> avoid when trying to write portable programs.

Thanks again, Jens.

Eric Sosman

unread,
Jun 2, 2012, 9:58:13 AM6/2/12
to
On 6/2/2012 9:12 AM, Jean-Christophe wrote:
> On 2 juin, 15:00, "BartC" :
>
>> Perhaps I'm missing the point somewhere,
>> but in that case, what's wrong with:
>> double a=0.0, b=0.0, .... ?
>> Do you just want to save some typing?
>
> I'm re-writing a messy 7500 lines source code into C,
> I kept all the same variables names to ease debugging
> and there are a LOT of functions, each one with its
> own LOT of local variables - all having different names.
> At least I want to initialise all of them to zero to
> avoid uninitialized variables fuck-up (if I may say so)

Usually it's better to leave the variable uninitialized than
to initialize it with an essentially meaningless value. As part
of their optimization efforts, most compilers perform data flow
analysis to answer questions like "Must we fetch the value of `x'
from memory, or is the value in CPU register 7 still valid?"
Such analysis will discover execution paths that might read a
variable before it's written, and the compiler can usually be told
to produce diagnostics when such paths are detected. The popular
gcc compiler, for example, has the "-Wuninitialized" flag (which
is implied by some others like "-Wall") to enable such warnings.

So if you have

double x;
for (int i = 0; i < N; ++i) {
if (array[i] < 0) {
x = array[i];
break;
}
}
printf ("%g\n", x);

... gcc can warn you that `x' might not have a value when used,
because the `if' might never trigger.

BUT if you change the first line to `double x = 0;' gcc will
NOT issue any such warning: It sees that `x' necessarily has a
value, regardless of what happens with the `if' statements. So
gcc will be silent and the output will be zero -- which is fine
if that was in fact the intent, but not so fine if you really
truly expected `x' to be the first negative value in `array',
and there isn't one.

In short, the bug (assuming `array' always has at least one
negative value) is still there, and all you've done is make the
bug's symptom predictable: Your supposedly negative value shows
up as zero. So, which would you rather have: A nice session with
the debugger, trying to discover why `x' isn't negative (or why a
long computation deriving something from `x' behaves strangely),
or a compile-time warning drawing your attention to a potential
problem?

> So it won't save me 'some' typing: I'll save a 'lot' of typing.

Seems to me the `lot' of typing does more harm than good.
Usually. YMMV. And so on.

--
Eric Sosman
eso...@ieee-dot-org.invalid

Noob

unread,
Jun 2, 2012, 10:05:46 AM6/2/12
to
Jean-Christophe wrote:

> The function f() has some local (double)
> which should all be initialized to zero :
>
> a = b = c = ... = y = z = 0.0;
>
> Can I use a shortcut like this :
>
> memset( &a, 0, number_of_variables * sizeof(double) );
>
> If yes, can I do this :
>
> memset( &a, 0, (&z - &a + sizeof(double)) );
>
> Like this :
>
> void f(void)
> {
> double a,b,c,d,...,x,y,z;
>
> memset( &a, 0, (unsigned int)( &z - &a + sizeof(double) ) );
>
> ...
> }

You can use an anonymous struct.
No need for memset, and portable; what more do you want? :-)

void foo(void)
{
struct { double a,b,c,d,e,f,g,h; } s = { 0 };
s.a = 42.0;
}

BartC

unread,
Jun 2, 2012, 10:08:00 AM6/2/12
to


"Jean-Christophe" <5...@free.fr> wrote in message
news:0e159ddf-1c62-4bc2...@a16g2000vby.googlegroups.com...
> On 2 juin, 15:35, j...@toerring.de (Jens Thoms Toerring) wrote:
>
>> > int i;
>> > double d1, d2;
>> > i = (int)( &d2 - &d1 ); // assuming &d2 > &d1
>> > then i == sizeof(double) // number of bytes
>> > because it's a difference of addresses
>> > whatever the variable type is.
>
>> I don't agree (...)
>
> Yes, sorry about that.
> What I had in mind was this :
>
>#include <stdio.h>
>double a,b;
>int main(void)
>{
> unsigned int ia = (unsigned int)&a;
> unsigned int ib = (unsigned int)&b;
> printf( "ib - ia = %u\r\n", ib - ia );
> printf( "ia - ib = %u\r\n", ia - ib );
> return 0;
>}


(char* can be used in place of unsigned int here.)

> Output :
> ib - ia = 8 // = sizeof(double)
> ia - ib = 4294967288 // 0xFFFFFFF8

The trouble is code like this:

double a;
char x;
double b;

On a machine which doesn't need to align doubles, it's quite possible that
(char*)&a - (char*)&b might be 9 bytes. (I don't know what C would do with
&a-&b in that case; possibly divide the 9 bytes by 8 to get 1, the answer
you expect.)

You might try this:

#include <stdio.h>
double a;
char x,y,z;
double b;

int main(void)
{
printf( "&a = %u\n", (unsigned int)&a);
printf( "&b = %u\n", (unsigned int)&b);
printf( "&x = %u\n", (unsigned int)&x);
printf( "&y = %u\n", (unsigned int)&y);
printf( "&z = %u\n", (unsigned int)&z);
return 0;
}

You'll probably find the addresses are all mixed up.

Even when *all* variables are doubles, you won't know which have the lowest
and highest addresses.

--
Bartc

Jean-Christophe

unread,
Jun 2, 2012, 10:37:04 AM6/2/12
to
On Jun 2, 4:08 pm, "BartC" :

> #include <stdio.h>
> double a;
> char x,y,z;
> double b;
> int main(void)
> { printf( "&a = %u\n", (unsigned int)&a);
> printf( "&b = %u\n", (unsigned int)&b);
> printf( "&x = %u\n", (unsigned int)&x);
> printf( "&y = %u\n", (unsigned int)&y);
> printf( "&z = %u\n", (unsigned int)&z);
> return 0;
> }

Output :

&a = 4221624
&b = 4221632
&x = 4221640
&y = 4221641
&z = 4221642

> You'll probably find the addresses are all mixed up.
> Even when *all* variables are doubles, you won't know
> which have the lowest and highest addresses.

:o)

James Kuyper

unread,
Jun 2, 2012, 10:59:26 AM6/2/12
to
On 06/02/2012 06:25 AM, Jean-Christophe wrote:
> On 2 juin, 12:06, jacob navia :
>
> | Can I use a shortcut like this (...)
>
>> No, in general you can't. The compiler may align the double variables at
>> a 16 byte boundary for instance, for performance reasons. That would
>> mean that the compiler would leave 8 bytes unused between each variable.
>> Another problem could be that the compiler doesn't store those variables
>> in a contiguos fashion but interleaves variables with other data (maybe
>> because alignment reasons)
>
> Okay, thanks.
>
> Since these variables are located in the stack,
> is there a way to FORCE the compiler to align them,
> using a compiler directive or something ?

Yes - but it's not a compiler directive, it's "something" called an
array. Instead of a, b, c, ..., z, use arr[0], arr[1], arr[2], ...,
arr[25]. Then you could use memset() on the entire array.

Keep in mind that memset() set the specified number of bytes,
interpreted as unsigned char, to the specified value. If that value is
0, on many systems that will cause the doubles to have a value of 0.0.
In C99, if __STDC_IEC_559__ is pre-defined by the implementation, that's
guaranteed to be true. However, if using C90, or if __STDC_IEC_559__ is
not pre-defined, an implementation is allowed to use a floating point
representation were all-bits-0 represents some other number entirely, or
even a NaN. It could even be a trap representation, in which case any
attempt to retrieve the value of the double objects after calling
memset() has undefined behavior.

The easiest way to portably guarantee that your floating point values
are zero-initialized is to do so explicitly:

double a=0, b=0, c=0, ..., z=0;

if you follow my suggestion, and use an array, you can save a lot of typing:

double arr[26] = {0};

You should understand what that does: it explicitly sets arr[0] to 0,
and implicitly zero-initializes the other 25 elements to 0. There's a
common misunderstanding of code like this; the easiest way to correct
that misunderstanding it to consider the following alternative:

double arr[26] = {1};

That does NOT set ever element of arr to 1. It explicitly sets arr[0] to
1, but the remaining 25 elements would still be implicitly zero-initialized.

>> An easy solution to your problem is:
>> #include <stdio.h>
>> int main(void) {
>> int i;
>> for (i='a'; i<= 'z'; i++) {
>> printf("\t%c = 0.0;\n",i);
>> }
>> }
>> Redirect the output to a file and insert
>> that file into your source code :-)
>
> That's not what I call 'easy'.

The :-) was your clue that it was a joke. He was basically hinting at
the 'a=0, b=0, c=0' approach I described above.
--
James Kuyper

BartC

unread,
Jun 2, 2012, 11:17:10 AM6/2/12
to
"Jean-Christophe" <5...@free.fr> wrote in message
news:7ff937d6-bd95-4235...@fr28g2000vbb.googlegroups.com...
> On Jun 2, 4:08 pm, "BartC" :

> Output :
>
> &a = 4221624
> &b = 4221632
> &x = 4221640
> &y = 4221641
> &z = 4221642

I tried it on four x86-32 compilers, and get the following (I've added an
extra term to highlight the differences):

&a = 4202528 0
&b = 4202544 16
&x = 4202552 -4
&y = 4202540 -12
&z = 4202536 -4

&a = 4214968 0
&b = 4214984 16
&x = 4214992 -7
&y = 4214977 -15
&z = 4214976 -1

&a = 4244000 0
&b = 4244008 8
&x = 4245044 1037
&y = 4245045 1
&z = 4245046 1

&a = 4231444 0
&b = 4231452 8
&x = 4231464 8
&y = 4231460 -4
&z = 4231468 8

The following was from a non-C compiler (although it's possible that some C
compiler could return this too):

&a = 1638040 0
&b = 1638028 -12
&x = 1638039 11
&y = 1638038 -1
&z = 1638037 -1

>> You'll probably find the addresses are all mixed up.
>> Even when *all* variables are doubles, you won't know
>> which have the lowest and highest addresses.
>
> :o)

While in the C examples, 'a' had the lower address, I don't see how this can
guaranteed (and you might expect it to have higher address, if allocated
first and the stack frame growing downwards). And in general you can't know
what order variables might be allocated in (perhaps in declaration order,
perhaps in alphabetical order, but it can be anything). Or some might not
exist in memory at all.

--
Bartc

Robert Wessel

unread,
Jun 2, 2012, 12:45:53 PM6/2/12
to
On Sat, 2 Jun 2012 06:12:27 -0700 (PDT), Jean-Christophe <5...@free.fr>
wrote:

>On 2 juin, 15:00, "BartC" :
>
>> Perhaps I'm missing the point somewhere,
>> but in that case, what's wrong with:
>> double a=0.0, b=0.0, .... ?
>> Do you just want to save some typing?
>
>I'm re-writing a messy 7500 lines source code into C,
>I kept all the same variables names to ease debugging
>and there are a LOT of functions, each one with its
>own LOT of local variables - all having different names.
>At least I want to initialise all of them to zero to
>avoid uninitialized variables fuck-up (if I may say so)
>
>So it won't save me 'some' typing: I'll save a 'lot' of typing.


7500 lines is a pretty small amount of code, but if the typing is
bothering you, set up a keyboard macro in your editor to insert the
"=0.0". If you're cleaning code up, finish that macro with a search
to the next command space or semi-colon (and another to just do the
search), so you can just flip through looking at each item, and then
hit one of two keys - one inserts the initialization and skips to the
next possible place you need one, the other skips.

Use your tools.

Jean-Christophe

unread,
Jun 2, 2012, 10:48:51 AM6/2/12
to
On Jun 2, 4:05 pm, Noob <root@localhost> wrote:

> You can use an anonymous struct. No need for
> memset, and portable; what more do you want? :-)

Yes, Jens pointed it to me and I agreed.

Ike Naar

unread,
Jun 2, 2012, 1:08:58 PM6/2/12
to
It's probably not crap, but -8 + (UINT_MAX+1) .

BartC

unread,
Jun 2, 2012, 1:31:08 PM6/2/12
to


"Jean-Christophe" <5...@free.fr> wrote in message
news:78b578f9-5187-4a81...@b1g2000vbb.googlegroups.com...
But, if the purpose now is to reduce typing, then sticking "s." in front of
every instance of a variable, sounds like more work than simply putting "=0"
once after it's declaration.

--
Bartc

Jens Thoms Toerring

unread,
Jun 2, 2012, 1:39:26 PM6/2/12
to
Jean-Christophe <5...@free.fr> wrote:
> What I had in mind was this :

> #include <stdio.h>
> double a,b;
> int main(void)
> {
> unsigned int ia = (unsigned int)&a;
> unsigned int ib = (unsigned int)&b;
> printf( "ib - ia = %u\r\n", ib - ia );
> printf( "ia - ib = %u\r\n", ia - ib );
> return 0;
> }

> Output :
> ib - ia = 8 // = sizeof(double)
> ia - ib = 4294967288 // 0xFFFFFFF8

Please note that also converting a pointer to an (unsigned)
int is not well-defined - e.g. an int could be too small
for hoding the value of a pointer. You might try uintptr_t
(an integer type capable of holding object pointers) instead
(but which is an optional type and requires c99). You could
also simply cast to char * (a cast that is guaranteed to
work) and you should get the same (or at least a comparable)
result

printf( "ib - ia = %lu\n",
( unsigned long ) ( ( char * ) &b - ( char * ) &a ) );

without having to convert the pointers to some integer type
(since the size of a char is 1 per definition). The only
possible catch here is that unsigned long could still be
too small to hold a difference between two pointers (and
using "%td" to have the difference between the two pointers
treated as a ptrdiff_t type suffers from the same problem).

BTW, I jut noticed something funny: the output of this program

#include <stdio.h>
double a, b;
int main( void )
{
double c, d;
printf( "global diff: %td\n", ( char * ) &a - ( char * ) &b );
printf( "local diff: %td\n", ( char * ) &c - ( char * ) &d );
return 0;
}

is

global diff: 8
local diff: -8

So the the order of the positions of the variables in memory
(at least on my machine and using gcc 4.6.1) is different for
local and global variables. While not terribly interesting it
could serve as an example that making assumption about the
memory layout of variables the compiler will use is at least
tricky;-)

> > considers appropriate. It would also be "correct" when
> > the result would always be 42.

> I got that !
> (Douglas Noel Adams, uh ?)

Got it all in one go;-)

Jens Thoms Toerring

unread,
Jun 2, 2012, 1:50:34 PM6/2/12
to
Sorry, but I didn't come up with the anonymous structure
trick. I don't think anybody before "Noob" mentioned it.

BartC

unread,
Jun 2, 2012, 2:02:23 PM6/2/12
to


"BartC" <b...@freeuk.com> wrote in message news:jqdaq0$v02$1...@dont-email.me...
> "Jean-Christophe" <5...@free.fr> wrote in message
> news:7ff937d6-bd95-4235...@fr28g2000vbb.googlegroups.com...
>> On Jun 2, 4:08 pm, "BartC" :
>
>> Output :
>>
>> &a = 4221624
>> &b = 4221632

> I tried it on four x86-32 compilers, and get the following (I've added an
> extra term to highlight the differences):

<Snip differences of +16, +16, +8, +8 between &a and &b (static)>

>>> You'll probably find the addresses are all mixed up.
>>> Even when *all* variables are doubles, you won't know
>>> which have the lowest and highest addresses.

> While in the C examples, 'a' had the lower address, I don't see how this
> can
> guaranteed (and you might expect it to have higher address, if allocated
> first and the stack frame growing downwards).

Jens' reply reminds me that, for some reason, your test was on static
variables. Rerunning the test on local variables, then generally a had the
higher address.

That's with just two doubles. Declaring doubles a,b,c,d,e (with other
variables interspersed), and displaying the difference between &d and &b, I
was getting results of +8, -16 and +16 over four compilers.

--
Bartc



Eric Sosman

unread,
Jun 2, 2012, 3:27:25 PM6/2/12
to
On 6/2/2012 1:39 PM, Jens Thoms Toerring wrote:
>[...]
> So the the order of the positions of the variables in memory
> (at least on my machine and using gcc 4.6.1) is different for
> local and global variables. While not terribly interesting it
> could serve as an example that making assumption about the
> memory layout of variables the compiler will use is at least
> tricky;-)

One implementation *alphabetized* global variables, apparently
during the link phase. I discovered this while trying to port
some code that assumed `double trouble, bubble;' would imply
`&trouble < &bubble', which turned out not to be the case ...

Specifically, the code was doing things like (paraphrased):

int checksum_start;
... data to be checksum-protected ...
int checksum_end;

for (int *p = &checksum_start; ++p < checksum_end; ) {
... accumulate checksum ...
}

When alphabetization put `checksum_end' *before* `checksum_start',
the fan was hit by the fertilizer.

--
Eric Sosman
eso...@ieee-dot-org.invalid

Jean-Christophe

unread,
Jun 2, 2012, 3:53:01 PM6/2/12
to
On 2 juin, 19:39, j...@toerring.de (Jens Thoms Toerring) wrote:

> (...) BTW, I jut noticed something funny:
> the output of this program
> #include <stdio.h>
> double a, b;
> int main( void )
> { double c, d;
> printf( "global diff: %td\n", ( char * ) &a - ( char * ) &b );
> printf( "local diff: %td\n", ( char * ) &c - ( char * ) &d );
> return 0;
> }
> is
> global diff: 8
> local diff: -8

I understand that : the address allocation for global
variables increases from the starting address,
while for local variables allocated on the stack
the stack pointer is decreased for each new variable.

> the result would always be 42.
>> (Douglas Noel Adams, uh ?)
> Got it all in one go ;-)

Well, on MY computer the correct
value is 41.999999999999999999

Jean-Christophe

unread,
Jun 2, 2012, 4:02:08 PM6/2/12
to
On 2 juin, 16:59, James Kuyper <jameskuy...@verizon.net> wrote:

> > Since these variables are located in the stack,
> > is there a way to FORCE the compiler to align them,
> > using a compiler directive or something ?

> Yes - but it's not a compiler directive

So it's "No" since it's not a compiler directive.

Jean-Christophe

unread,
Jun 2, 2012, 3:58:12 PM6/2/12
to
On 2 juin, 21:27, Eric Sosman <esos...@ieee-dot-org.invalid> wrote:

> One implementation *alphabetized* global variables, apparently
> during the link phase. I discovered this while trying to port
> some code that assumed `double trouble, bubble;' would imply
> `&trouble < &bubble', which turned out not to be the case ...
> Specifically, the code was doing things like (paraphrased):
> int checksum_start;
> ... data to be checksum-protected ...
> int checksum_end;
> for (int *p = &checksum_start; ++p < checksum_end; ) {
> ... accumulate checksum ...
> }
>
> When alphabetization put `checksum_end' *before* `checksum_start',
> the fan was hit by the fertilizer.

That's funny because some years ago
I implemented something like this
... in asm, so it worked pretty well.

Eric Sosman

unread,
Jun 2, 2012, 4:15:27 PM6/2/12
to
On 6/2/2012 3:58 PM, Jean-Christophe wrote:
> On 2 juin, 21:27, Eric Sosman<esos...@ieee-dot-org.invalid> wrote:
>
>> One implementation *alphabetized* global variables, apparently
>> during the link phase. I discovered this while trying to port
>> some code that assumed `double trouble, bubble;' would imply
>> `&trouble< &bubble', which turned out not to be the case ...
>> Specifically, the code was doing things like (paraphrased):
>> int checksum_start;
>> ... data to be checksum-protected ...
>> int checksum_end;
>> for (int *p =&checksum_start; ++p< checksum_end; ) {
>> ... accumulate checksum ...
>> }
>>
>> When alphabetization put `checksum_end' *before* `checksum_start',
>> the fan was hit by the fertilizer.
>
> That's funny because some years ago
> I implemented something like this
> ... in asm, so it worked pretty well.

Okay, but what has that to do with C? If a construct has some
particular effect in an assembler, do you expect to get the same
outcome in C? If it has some particular effect in Java, do you
expect the same outcome in C? If it has some particular effect in
German, do you expect the same outcome in C?

Don't confuse the tool you're using with the tool you're not.

--
Eric Sosman
eso...@ieee-dot-org.invalid

BartC

unread,
Jun 2, 2012, 4:16:12 PM6/2/12
to


"Jean-Christophe" <5...@free.fr> wrote in message
news:9c25c022-dab8-4e7e...@b1g2000vbb.googlegroups.com...
> On 2 juin, 19:39, j...@toerring.de (Jens Thoms Toerring) wrote:
>
>> (...) BTW, I jut noticed something funny:
>> the output of this program
>> #include <stdio.h>
>> double a, b;
>> int main( void )
>> { double c, d;
>> printf( "global diff: %td\n", ( char * ) &a - ( char * ) &b );
>> printf( "local diff: %td\n", ( char * ) &c - ( char * ) &d );
>> return 0;
>> }
>> is
>> global diff: 8
>> local diff: -8
>
> I understand that : the address allocation for global
> variables increases from the starting address,
> while for local variables allocated on the stack
> the stack pointer is decreased for each new variable.

I still don't think you appreciate that these things can be unpredictable
(because addresses aren't allocated at the instant the identifier is
encountered in the source). Try this much simpler test:

#include <stdio.h>
double three;
double four;
int main(void)
{

printf( "&three = %u\n", (unsigned int)&three);
printf( "&four = %u\n", (unsigned int)&four);
printf( "&four-&three = %d\n", (int)&four-(int)&three);
return 0;
}

Which do you think has the lower address, 'three' or 'four'? Of my four
compilers, two gave a difference of -8, and two of +8.

--
Bartc

Jens Thoms Toerring

unread,
Jun 2, 2012, 5:18:22 PM6/2/12
to
Jean-Christophe <5...@free.fr> wrote:
> On 2 juin, 19:39, j...@toerring.de (Jens Thoms Toerring) wrote:

> > (...) BTW, I jut noticed something funny:
> > the output of this program
> > #include <stdio.h>
> > double a, b;
> > int main( void )
> > { double c, d;
> > printf( "global diff: %td\n", ( char * ) &a - ( char * ) &b );
> > printf( "local diff: %td\n", ( char * ) &c - ( char * ) &d );
> > return 0;
> > }
> > is
> > global diff: 8
> > local diff: -8

> I understand that : the address allocation for global
> variables increases from the starting address,
> while for local variables allocated on the stack
> the stack pointer is decreased for each new variable.

Let's say it fits your mental model of what's going on
under the hood. This is quite often correct but sometimes
also can lead on astray. Learning assembler before C has
for sure its advantages, e.g. pointers, which seem to con-
fuse quite a number of people at first, are something ob-
vious etc. The danger is that one finds a lot of things
that seem to have an easy explanation since there seem to
be an obvious fit to how one would do it in assembler and
is thus sometimes tempted to wrongly extrapolate from that
(or take it for the truth). Knowing assembler (and maybe
even how the linker works on a certain machine) can thus
be quite helpful to build a mental image of how things
probably are working, but one has to be careful not to
blindly assume that things really work exactly as one
would expect from that. Can be a bit painful going from
"I know exactly what the machine is doing" to "what are
the damnded rules for this strange behaviour in C";-)

In the end I found it more useful trying to avoid to look
at C through my "assembler goggles" and instead accept it
as something different, having its own rules that I had to
learn and that not always could be easily explained in terms
of what I knew from assembler (on the bery limited set of
architectures I learned it for). Admittedly, that can be
harder than with languages that are that far removed from
assembler that one has no idea at all anymore what might
be going on under the hood.

> > the result would always be 42.
> >> (Douglas Noel Adams, uh ?)
> > Got it all in one go ;-)

> Well, on MY computer the correct
> value is 41.999999999999999999

Eric Sosman

unread,
Jun 2, 2012, 5:38:52 PM6/2/12
to
On 6/2/2012 5:18 PM, Jens Thoms Toerring wrote:
> [...] Learning assembler before C has
> for sure its advantages, e.g. pointers, which seem to con-
> fuse quite a number of people at first, are something ob-
> vious etc. [...]

A bad effect of learning assembly languages before C is
that one is tempted to think "Pointers? Oh, I get it: They're
just addresses, and I already know about addresses."

What's wrong with thinking "Pointers are addresses?" Here's
an illustration: In an assembly setting you might be told that
the R1 register holds an address and be asked to test whether the
value R1 points to is zero. Are you ready to write the test? No,
you need to ask "What kind of value does R1 point at? A single
byte, a two-byte integer, an eight-byte floating-point number, or
what?"

You never need to ask such questions in C, because a pointer
is not a bare address: It is an address *and a type*. If you're
told that the variable R1 points somewhere and you're asked to
test whether the pointee is zero, you're all set: The type of R1
is known, hence the type it points at is known, and you have all
the information you need: `if (*R1 == 0)', and you're off to the
races (if R1 points to something that's not comparable to zero
the compiler will complain -- but in that case the "test for zero"
question made no sense in the first place).

It seems to me from some of the rather peculiar subtractions
he's attempted that Jean-Christophe may harbor this very confusion
between typed pointers and assembly-style "bare" addresses.

--
Eric Sosman
eso...@ieee-dot-org.invalid

Keith Thompson

unread,
Jun 2, 2012, 5:50:28 PM6/2/12
to
Jean-Christophe <5...@free.fr> writes:
> On 2 juin, 19:39, j...@toerring.de (Jens Thoms Toerring) wrote:
>
>> (...) BTW, I jut noticed something funny:
>> the output of this program
>> #include <stdio.h>
>> double a, b;
>> int main( void )
>> { double c, d;
>> printf( "global diff: %td\n", ( char * ) &a - ( char * ) &b );
>> printf( "local diff: %td\n", ( char * ) &c - ( char * ) &d );
>> return 0;
>> }
>> is
>> global diff: 8
>> local diff: -8
>
> I understand that : the address allocation for global
> variables increases from the starting address,
> while for local variables allocated on the stack
> the stack pointer is decreased for each new variable.

Global variables are allocated wherever the &^*%$ the implementation
decides to allocate them.

Local variables are allocated wherever the &^*%$ the implementation
decides to allocate them.

You should not make *any* assumptions about what any particular
implementation does.

Well, that might not *quite* be true, but it's very rare that it would
make any sense to make such assumptions. The result will be code that
can break badly when compiled on a different system, with a different
version of the same compiler, with the same compiler and different
optimization options, or with exactly the same options during a
different phase of the Moon.

You seem to have started with a certain set of assumptions based on the
behavior of one particular implementation, and are now trying to
understand systems that behave differently. You're likely to have
better luck by trying to understand just what the language does and does
not guarantee, and then understanding individual implementations in
terms of the choice they make within the limits imposed by the standard.

Don't worry about how variables are allocated; instead, write code that
will work regardless of how they're allocated.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson

unread,
Jun 2, 2012, 5:51:47 PM6/2/12
to
It's "Yes" since it's an "or something".

Jens Thoms Toerring

unread,
Jun 2, 2012, 6:15:46 PM6/2/12
to
Yes, that could be one of things I had to unlearn the hard
way... C makes a lot of things much more simple and safer,
but it can take some time to learn what they are, how they
work and then to appreciate them in the end;-) To be honest,
for about the first 5 years of using C I was blissfully igno-
rant of a lot of potential problems in the code I wrote - I
was programming on an architecture were I knew the assembler,
I had studied how the linker works in detail etc. and there
were no real surprises - everything seemed to fit quite nicely
and I considered myself to be a quite competent programmer. And
then came the day when I had to port one of my programs to a
different architecture - you can guess the rest of the story...
After a lot of pain (and quite a bit of deflation of my self-
esteem;-) I started to learn that C isn't assembler in dis-
guise - and lurking in comp.lang.c for some of time hope-
fully helped to cure some of the worst of my stupid mis-
understandings;-)

Jean-Christophe

unread,
Jun 3, 2012, 3:13:13 AM6/3/12
to
On 2 juin, 23:18, j...@toerring.de (Jens Thoms Toerring) wrote:

| I understand that : the address allocation for global
| variables increases from the starting address,
| while for local variables allocated on the stack
| the stack pointer is decreased for each new variable.

> Let's say it fits your mental model of what's going on
> under the hood. This is quite often correct but sometimes
> also can lead on astray. Learning assembler before C has
> for sure its advantages, e.g. pointers, which seem to con-
> fuse quite a number of people at first, are something ob-
> vious etc. The danger is that one finds a lot of things
> that seem to have an easy explanation since there seem to
> be an obvious fit to how one would do it in assembler and
> is thus sometimes tempted to wrongly extrapolate from that
> (or take it for the truth). Knowing assembler (and maybe
> even how the linker works on a certain machine) can thus
> be quite helpful to build a mental image of how things
> probably are working, but one has to be careful not to
> blindly assume that things really work exactly as one
> would expect from that.

You're perfectly right.
As an electronician I just can't avoid thinking
that variables are stored somewhere in the hardware,
(RAM, uP register, a buffer in some I/O chip, or even
by the use of the capacitive property of a bus itself)
and I perfectly understand why an IT guy will avoid such
considerations. Abstraction of the hardware is needed
for portability, but is the contrary of electronics.
Anyway this is a reflex and I can't help it.
Now, to take advantage of this, one needs a perfect
knowledge of all the underlying, which is true for
electronics w/ uP I designed myself, but is not
always true for an implementation of code on a PC.


> Can be a bit painful going from
> "I know exactly what the machine is doing" to "what are
> the damnded rules for this strange behaviour in C";-)
> In the end I found it more useful trying to avoid to look
> at C through my "assembler goggles" and instead accept it
> as something different, having its own rules that I had to
> learn and that not always could be easily explained in terms
> of what I knew from assembler (on the bery limited set of
> architectures I learned it for).

I never said that knowing asm makes me a C programmer.
I'm not *guessing* how C works, to try to use it like asm.
(but I mix C & asm when it's convenient/needed/powerful)
I just asked a question about an idea which turns out to
be something better to forget : ok, no problem, thanks !


> Admittedly, that can be
> harder than with languages that are that far removed from
> assembler that one has no idea at all anymore what might
> be going on under the hood.

Arch ! I don't use these couternature things :o)
I think C is a terrific language, because i can understand it,
and use it efficiently. I know I have to avoid superimposing
one field to another - otherwise I would't have posted here.

Jean-Christophe

unread,
Jun 3, 2012, 3:51:26 AM6/3/12
to
On 2 juin, 23:38, Eric Sosman <esos...@ieee-dot-org.invalid> wrote:

> A bad effect of learning assembly languages before C is
> that one is tempted to think "Pointers? Oh, I get it:
> They're just addresses, and I already know about addresses."
> What's wrong with thinking "Pointers are addresses?" Here's
> an illustration: In an assembly setting you might be told that
> the R1 register holds an address and be asked to test whether the
> value R1 points to is zero. Are you ready to write the test? No,
> you need to ask "What kind of value does R1 point at? A single
> byte, a two-byte integer, an eight-byte floating-point number, or
> what?"
> You never need to ask such questions in C, because a pointer
> is not a bare address: It is an address *and a type*. If you're
> told that the variable R1 points somewhere and you're asked to
> test whether the pointee is zero, you're all set: The type of R1
> is known, hence the type it points at is known, and you have all
> the information you need: `if (*R1 == 0)', and you're off to the
> races (if R1 points to something that's not comparable to zero
> the compiler will complain -- but in that case the "test for zero"
> question made no sense in the first place).

Yes, and if the type is integer (for instance) you don't
have to know if it's big-endian or little-endian, if it's
a float you don't have to know how it's coded, etc ...

> It seems to me from some of the rather peculiar subtractions
> he's attempted that Jean-Christophe may harbor this very confusion
> between typed pointers and assembly-style "bare" addresses.

The problem is not the fact that a difference of two pointers
on a same data type has no sense, the problem is that I should
not assume anything about the actual addresses of the variables.
Now I understand why, thanks for helping me,
but please, do not infer that I know nothing at all.

Now, data type implementation does exist in asm,
event if it's only in the head of the programmer.
So if you're asked to test if an address points to a zero
value, first of all you'll ask the question: test for what ?
A bit (which one), a byte, an integer (how many bytes)
a float (how is it coded) and so on.

io_x

unread,
Jun 3, 2012, 4:33:03 AM6/3/12
to

"Jean-Christophe" <5...@free.fr> ha scritto nel messaggio
news:8ba1c5dd-15a9-4ffc...@5g2000vbf.googlegroups.com...
> Sorry about the misunderstanding,
> this is what I meant :
>
> #include <stdio.h>
> double a,b;
> int main(void)
> {
> unsigned int ia = (unsigned int)&a;
> unsigned int ib = (unsigned int)&b;
> printf( "ib - ia = %u\r\n", ib - ia );
> printf( "ia - ib = %u\r\n", ia - ib );
> return 0;
> }
>
>
> ib - ia = 8 // = sizeof(double)
> ia - ib = 4294967288 // crap

it is the pointer way that is a crap
(4294967288+8)0xFFFFFFFF=0x100000000 mod 0xFFFFFFFF=0
ia - ib + ib - ia = 0



io_x

unread,
Jun 3, 2012, 4:32:55 AM6/3/12
to

"Jens Thoms Toerring" <j...@toerring.de> ha scritto nel messaggio
news:a2u8bh...@mid.uni-berlin.de...
> Jean-Christophe <5...@free.fr> wrote:
>> The function f() has some local (double)
>> which should all be initialized to zero :
>
>> double a,b,c,d,...,x,y,z;
>> a = b = c = ... = y = z = 0.0;
>
>> Can I use a shortcut like this :
>
>> memset( &a, 0, number_of_variables * sizeof(double) );
>
> Your idea has a number of problems: for once, while it is
> not unlikely that they are all in consecutive memory lo-
> cations, that's not guaranteed - the simplest practical
> reason would be that the compiler finds that one or more
> of the variables is not really needs to be kept in memory
> and can be optimized to reside in a CPU register only. Se-
> cond, even if that wouldn't be an issue, there is no reason
> at all that 'a' should be at the lowest address - quite
> often the variable defined last is the one with the lowest
> address - this is completely at the discretion of the com-
> piler. Finally not on all systems a 0.0 value is represen-
> ted by all bits set to zero.

yes, the compiler can do that, the compiler can do this etc
and you have no idea on how data appear...



io_x

unread,
Jun 3, 2012, 5:32:40 AM6/3/12
to

"io_x" <a...@b.c.invalid> ha scritto nel messaggio
news:4fcb2256$0$1375$4faf...@reader2.news.tin.it...
(4294967288+8)%0x100000000=0x100000000 & 0xFFFFFFFF=0



Malcolm McLean

unread,
Jun 3, 2012, 2:46:52 PM6/3/12
to
בתאריך יום שבת, 2 ביוני 2012 22:38:52 UTC+1, מאת Eric Sosman:
>
> A bad effect of learning assembly languages before C is
> that one is tempted to think "Pointers? Oh, I get it: They're
> just addresses, and I already know about addresses."
>
> What's wrong with thinking "Pointers are addresses?" Here's
> an illustration: In an assembly setting you might be told that
> the R1 register holds an address and be asked to test whether the
> value R1 points to is zero. Are you ready to write the test? No,
> you need to ask "What kind of value does R1 point at? A single
> byte, a two-byte integer, an eight-byte floating-point number, or
> what?"
>
In assembly, if you're passed an address you need to know why you've been passed it, what data you are meant to read there or write there, and in what format. In C, you need to know why you've been passed a pointer, whether you're meant to read the data and or write to the buffer, and how big the buffer is. But pointers are tagged with the format. That's because C is a slightly higher level language than assembler. However often C pointers are void *s, in which case you have to know the format.
The difference is very slight. Pointers cause problems for newbie programmers. Howwever I learned C after I had learnt assembler. So I said "*, what does that mean, it's clearly not a multiplication? Oh, it's the indirection operator." That was that. Pointers weren't a problem for me. malloc() was more of a leap, I'd always used fixed buffers in assembler. So I initially thought you could just ignore malloc(), it was an unimportant special extension.

David Brown

unread,
Jun 3, 2012, 4:25:21 PM6/3/12
to
On Sat, 02 Jun 2012 05:37:24 -0700, Jean-Christophe wrote:

> All right then.
> I understand I made the error of expanding my knowledge of
> 'micro-controllers' C compilers to the 'PC' C compilers. Some things
> won't work at all, and if they do it's even worse because it's just
> luck.
>
> Thanks for taking time.

If you are used to microcontrollers, then many of your assumptions are
even worse (although it's fair enough to assume that a float with all
zero bytes will be 0.0 - I can't think of any microcontroller which
doesn't follow that, even though most don't follow IEEE exactly).

It's quite simple - when you declare a local variable, you let the
compiler decide. You have no guarantees as to whether the variables are
put in memory at all, or will be held in registers, or will even be
removed entirely by the optimiser. Even if they are put in memory, you
know nothing about their ordering, nor their lifetimes, nor the sharing
of data.

In the world of microcontroller programming, no one bar a few beginners
would use a compiler without enabling optimisation, because slower and
bigger code means more expensive hardware. So while a few PC programmers
might forget to enable optimisations, because speed and space are cheap
on a PC, it should not happen in micrcontroller programming. And the
only way you could think that the compiler would allocate the local
variables "a, b, c..." blindly on the stack in the declared order is if
you deliberately cripple your compiler by not enabling optimisation.

Remember, premature optimisation is the root of all evil. Write your
source code clearly and simply, and let the /compiler/ do the job of
making good object code from it.

David Brown

unread,
Jun 3, 2012, 4:27:41 PM6/3/12
to
This is where "stuct" would be useful...

David Brown

unread,
Jun 3, 2012, 4:34:57 PM6/3/12
to
On Sat, 02 Jun 2012 12:53:01 -0700, Jean-Christophe wrote:

> On 2 juin, 19:39, j...@toerring.de (Jens Thoms Toerring) wrote:
>
>> (...) BTW, I jut noticed something funny: the output of this program
>> #include <stdio.h>
>> double a, b;
>> int main( void )
>> { double c, d;
>> printf( "global diff: %td\n", ( char * ) &a - ( char * ) &b );
>> printf( "local diff: %td\n", ( char * ) &c - ( char * ) &d );
>> return 0;
>> }
>> is
>> global diff: 8
>> local diff: -8
>
> I understand that : the address allocation for global variables
> increases from the starting address, while for local variables allocated
> on the stack the stack pointer is decreased for each new variable.
>

No, that's wrong in several ways.

It is very common that the memory layout on microcontrollers is to put
code and read-only data in flash. Then from the bottom of ram you get
the initialised data section, then the bss (uninitialised data,
automatically zeroed by the startup code). This is followed by the heap,
which grows upwards. The stack starts at the top of ram and grows
downwards.

The first mistake, however, is to assume this is always the case - it's
common, but not universal. There are even systems that split the stack
into a data stack and a return stack.

Secondly, although the stack generally decreases for each function call,
the common method is for the function prologue to allocate a frame size
and move the stack pointer down that size. But local data is allocated
upwards within that frame (well, mostly upwards - it is also re-used, and
passed around registers, and maybe re-arranged for greater efficiency).

Thirdly, within each section of data, items are often re-arranged. They
may be ordered by source module, alphabetically, by size, by "hot" and
"cold" usage, etc.

This is why the C standards are very clear - when you write "double a,
b;", you cannot say /anything/ about their relative positioning. They
may not even be allocated anywhere - even taking their address does not
necessarily force them to be allocated in ram if the compiler can figure
out a way to avoid it.

David Brown

unread,
Jun 3, 2012, 4:41:06 PM6/3/12
to
On Sat, 02 Jun 2012 09:58:13 -0400, Eric Sosman wrote:

> On 6/2/2012 9:12 AM, Jean-Christophe wrote:
>> On 2 juin, 15:00, "BartC" :
>>
>>> Perhaps I'm missing the point somewhere, but in that case, what's
>>> wrong with:
>>> double a=0.0, b=0.0, .... ?
>>> Do you just want to save some typing?
>>
>> I'm re-writing a messy 7500 lines source code into C, I kept all the
>> same variables names to ease debugging and there are a LOT of
>> functions, each one with its own LOT of local variables - all having
>> different names. At least I want to initialise all of them to zero to
>> avoid uninitialized variables fuck-up (if I may say so)
>
> Usually it's better to leave the variable uninitialized than
> to initialize it with an essentially meaningless value. As part of
> their optimization efforts, most compilers perform data flow analysis to
> answer questions like "Must we fetch the value of `x' from memory, or is
> the value in CPU register 7 still valid?" Such analysis will discover
> execution paths that might read a variable before it's written, and the
> compiler can usually be told to produce diagnostics when such paths are
> detected. The popular gcc compiler, for example, has the
> "-Wuninitialized" flag (which is implied by some others like "-Wall") to
> enable such warnings.
>
> So if you have
>
> double x;
> for (int i = 0; i < N; ++i) {
> if (array[i] < 0) {
> x = array[i];
> break;
> }
> }
> printf ("%g\n", x);
>
> ... gcc can warn you that `x' might not have a value when used, because
> the `if' might never trigger.
>
> BUT if you change the first line to `double x = 0;' gcc will
> NOT issue any such warning: It sees that `x' necessarily has a value,
> regardless of what happens with the `if' statements. So gcc will be
> silent and the output will be zero -- which is fine if that was in fact
> the intent, but not so fine if you really truly expected `x' to be the
> first negative value in `array', and there isn't one.
>
> In short, the bug (assuming `array' always has at least one
> negative value) is still there, and all you've done is make the bug's
> symptom predictable: Your supposedly negative value shows up as zero.
> So, which would you rather have: A nice session with the debugger,
> trying to discover why `x' isn't negative (or why a long computation
> deriving something from `x' behaves strangely), or a compile-time
> warning drawing your attention to a potential problem?
>
>> So it won't save me 'some' typing: I'll save a 'lot' of typing.
>
> Seems to me the `lot' of typing does more harm than good.
> Usually. YMMV. And so on.

This sounds to me like a /very/ important point.

To the OP - it's helpful to say what you are really trying to achieve,
rather than just one aspect of the implementation.

Noob

unread,
Jun 5, 2012, 3:12:40 AM6/5/12
to
David Brown wrote:

> This is where "stuct" would be useful...

"stuct in the middle with you" ?

David Brown

unread,
Jun 5, 2012, 3:21:23 AM6/5/12
to
It is the standard way of controlling the ordering of data:

#define stuct struct

stuct {
int checksum_start;
... data to be checksum protected
int checksum_end;
} checkedData;


Don't you use stucts for this sort of thing? :-)
0 new messages