Velocity Reviews > Q: Local variables initialization shortcut.

# Q: Local variables initialization shortcut.

Jens Thoms Toerring
Guest
Posts: n/a

 06-02-2012
Jean-Christophe <(E-Mail Removed)> wrote:
> On 2 juin, 13:55, (E-Mail Removed) (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
--
\ Jens Thoms Toerring ___ http://www.velocityreviews.com/forums/(E-Mail Removed)
\__________________________ http://toerring.de

Jean-Christophe
Guest
Posts: n/a

 06-02-2012
On 2 juin, 15:35, (E-Mail Removed) (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
Guest
Posts: n/a

 06-02-2012
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 ****-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
(E-Mail Removed)d

Noob
Guest
Posts: n/a

 06-02-2012
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
Guest
Posts: n/a

 06-02-2012

"Jean-Christophe" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> On 2 juin, 15:35, (E-Mail Removed) (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
Guest
Posts: n/a

 06-02-2012
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.

)

Jean-Christophe
Guest
Posts: n/a

 06-02-2012
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.

James Kuyper
Guest
Posts: n/a

 06-02-2012
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
Guest
Posts: n/a

 06-02-2012
"Jean-Christophe" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
> 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.

>
> )

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

Ike Naar
Guest
Posts: n/a

 06-02-2012
On 2012-06-02, Jean-Christophe <(E-Mail Removed)> wrote:
> 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's probably not crap, but -8 + (UINT_MAX+1) .

 Thread Tools

 Posting Rules You may not post new threads You may not post replies You may not post attachments You may not edit your posts BB code is On Smilies are On [IMG] code is On HTML code is OffTrackbacks are On Pingbacks are On Refbacks are Off Forum Rules

 Similar Threads Thread Thread Starter Forum Replies Last Post Severin Ecker C++ 9 03-11-2010 11:41 PM auspicious C++ 0 09-25-2008 10:02 PM Sullivan WxPyQtKinter Python 10 11-08-2007 02:51 PM Tammo Tjarks Ruby 2 09-13-2007 06:29 PM Michal Kwiatkowski Python 5 02-27-2006 02:56 AM

Advertisments