Q: Local variables initialization shortcut.

  • Thread starter Jean-Christophe
  • Start date
J

Jean-Christophe

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) ) );

...
}
 
J

jacob navia

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

:)
 
I

Ian Collins

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.
 
J

Jean-Christophe

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 !
 
J

Jean-Christophe

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'.
 
J

Jens Thoms Toerring

Jean-Christophe said:
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
 
B

BartC

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 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...
 
J

Jean-Christophe

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.
 
J

Jean-Christophe

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 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)
 
B

BartC

Jean-Christophe said:
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.)
 
B

BartC

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.
 
J

Jens Thoms Toerring

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.
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.
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
 
J

Jean-Christophe

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.
 
J

Jean-Christophe

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.
 
J

Jean-Christophe

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.


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.

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.


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.

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.

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.

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.
 
E

Eric Sosman

Jean-Christophe said:
[...]
'&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.
 
J

Jean-Christophe

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
 
J

Jean-Christophe

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
 
B

BartC

Jean-Christophe said:
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.
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.
 
J

Jean-Christophe

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)

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

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

Sure. Thanks Bartc.
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top