From: Wolfgang Lorenz on
This works fine with VC5. The cast allows me to concentrate on my
algorithm and not having to worry about if the array contains real data
or just pointers to it.

But when compiling with VC2008, I get 3 warnings:

(30) : warning C4700: uninitialized local variable 'i_ref' used
(35) : warning C4700: uninitialized local variable 'i_ptr' used
(47) : warning C4700: uninitialized local variable 'i_ref' used

And it works only in release mode. With _DEBUG enabled, it stops with a
runtime error :(

-- Wolfgang

// make loop counter local to prevent error C2374 with old compilers
#if _MSC_VER <= 1200 // behaviour unknown for VC6 < version < VC2005
#define for if (1) for
#endif

#include <stdio.h>

template<class T> inline T& cast_to(T&, T& x) { return x; }
template<class T> inline T& cast_to(T&, T* x) { return *x; }
template<class T> inline T* cast_to(T*, T& x) { return &x; }

#define lengthof(a) (sizeof(a) / sizeof(a[0]))
#define foreach(e, T, a) for (int e##i = 0; e##i < lengthof(a); e##i++)
{ T e = cast_to(e, (a)[e##i]); /##/

int is[] = { 1, 2, 3 };

int* pis[] = { &is[2], &is[1], &is[0] };

void main() {

printf("\n\nIterating through the data:\n");

printf("\nforeach (i_cpy, int , is) =");
foreach (i_cpy, int , is) {
printf(" %d", i_cpy);
}

printf("\nforeach (i_ref, int&, is) =");
foreach (i_ref, int&, is) {
printf(" %d", i_ref);
}

printf("\nforeach (i_ptr, int*, is) =");
foreach (i_ptr, int*, is) {
printf(" %d", *i_ptr);
}

printf("\n\nIterating through the pointers:\n");

printf("\nforeach (i_cpy, int , pis) =");
foreach (i_cpy, int , pis) {
printf(" %d", i_cpy);
}

printf("\nforeach (i_ref, int&, pis) =");
foreach (i_ref, int&, pis) {
printf(" %d", i_ref);
}

printf("\nforeach (i_ptr, int*, pis) =");
foreach (i_ptr, int*, pis) {
printf(" %d", *i_ptr);
}

printf("\n\nREADY.\n");
getchar();
}
From: Ike Naar on
In article <4b41b2dc$0$6590$9b4e6d93(a)newsspool3.arcor-online.net>,
Wolfgang Lorenz <wl924236(a)arcor.de> wrote:
>This works fine with VC5. The cast allows me to concentrate on my
>algorithm and not having to worry about if the array contains real data
>or just pointers to it.
>
>But when compiling with VC2008, I get 3 warnings:
>
>(30) : warning C4700: uninitialized local variable 'i_ref' used
>(35) : warning C4700: uninitialized local variable 'i_ptr' used
>(47) : warning C4700: uninitialized local variable 'i_ref' used
>
>And it works only in release mode. With _DEBUG enabled, it stops with a
>runtime error :(
>
>-- Wolfgang
>
>// make loop counter local to prevent error C2374 with old compilers
>#if _MSC_VER <= 1200 // behaviour unknown for VC6 < version < VC2005
> #define for if (1) for
>#endif

What is the purpose of this macro?

>#include <stdio.h>
>
>template<class T> inline T& cast_to(T&, T& x) { return x; }
>template<class T> inline T& cast_to(T&, T* x) { return *x; }
>template<class T> inline T* cast_to(T*, T& x) { return &x; }
>
>#define lengthof(a) (sizeof(a) / sizeof(a[0]))
>#define foreach(e, T, a) for (int e##i = 0; e##i < lengthof(a); e##i++)
>{ T e = cast_to(e, (a)[e##i]); /##/

There are a few problems with this macro, and as a result, your code
does not even compile on my machine.

1) Apparently the #define foreach text is supposed to be the rest
of the line followed by the next line; that means the newline at the end
of the first line should be escaped with a backslash:

#define foreach(e, T, a) for (int e##i = 0; e##i < lengthof(a); e##i++) \
{ T e = cast_to(e, (a)[e##i]); /##/

2) The text of this macro contains an opening brace, but not the matching
closing brace; probably the caller of the macro is expected to provide the
closing brace. But, later on in the program, the macro calls are followed
by both an opening brace and a closing brace, as a result the braces at the
call sites don't match.

3) What is the purpose of the /##/ construct?
My compiler (gcc) does not accept it.

If I fix these problems (i.e. add the backslash, remove the spurious opening
brace at the call sites, and remove the /##/) then the program compiles and
seems to run okay.

>int is[] = { 1, 2, 3 };
>
>int* pis[] = { &is[2], &is[1], &is[0] };
>
>void main() {
>
> printf("\n\nIterating through the data:\n");
>
> printf("\nforeach (i_cpy, int , is) =");
> foreach (i_cpy, int , is) {
> printf(" %d", i_cpy);
> }
>
> printf("\nforeach (i_ref, int&, is) =");
> foreach (i_ref, int&, is) {
> printf(" %d", i_ref);
> }
>
> printf("\nforeach (i_ptr, int*, is) =");
> foreach (i_ptr, int*, is) {
> printf(" %d", *i_ptr);
> }
>
> printf("\n\nIterating through the pointers:\n");
>
> printf("\nforeach (i_cpy, int , pis) =");
> foreach (i_cpy, int , pis) {
> printf(" %d", i_cpy);
> }
>
> printf("\nforeach (i_ref, int&, pis) =");
> foreach (i_ref, int&, pis) {
> printf(" %d", i_ref);
> }
>
> printf("\nforeach (i_ptr, int*, pis) =");
> foreach (i_ptr, int*, pis) {
> printf(" %d", *i_ptr);
> }
>
> printf("\n\nREADY.\n");
> getchar();
>}

Here's the output:


Iterating through the data:

foreach (i_cpy, int , is) = 1 2 3
foreach (i_ref, int&, is) = 1 2 3
foreach (i_ptr, int*, is) = 1 2 3

Iterating through the pointers:

foreach (i_cpy, int , pis) = 3 2 1
foreach (i_ref, int&, pis) = 3 2 1
foreach (i_ptr, int*, pis) = 3 2 1

READY.

From: Ike Naar on
In article <4b41b2dc$0$6590$9b4e6d93(a)newsspool3.arcor-online.net>,
Wolfgang Lorenz <wl924236(a)arcor.de> wrote:
>This works fine with VC5. The cast allows me to concentrate on my
>algorithm and not having to worry about if the array contains real data
>or just pointers to it.
>
>But when compiling with VC2008, I get 3 warnings:
>
>(30) : warning C4700: uninitialized local variable 'i_ref' used
>(35) : warning C4700: uninitialized local variable 'i_ptr' used
>(47) : warning C4700: uninitialized local variable 'i_ref' used
>
>And it works only in release mode. With _DEBUG enabled, it stops with a
>runtime error :(
>
>-- Wolfgang
>
>// make loop counter local to prevent error C2374 with old compilers
>#if _MSC_VER <= 1200 // behaviour unknown for VC6 < version < VC2005
> #define for if (1) for
>#endif
>
>#include <stdio.h>

Do you realize that the ``#define for'' may alter the semantics of
for statements that appear later in the code? E.g. those in <stdio.h> ?

For example, suppose you have the following:

if (condition)
for (/*whatever*/)
do_a;
else
do_b;

If condition is false, this for statement should normally execute do_b.

Now see what happens when ``for'' is redefined as ``if (1) for''.
The code becomes:

if (condition)
if (1) for (/*whatever*/)
do_a;
else
do_b;

The indentation is now misleading, so let's fix it:

if (condition)
if (1) for (/*whatever*/)
do_a;
else
do_b;

Now, you see that when condition is false, do_b is *not* executed anymore.

My advice is to remove the ``for'' macro, or, at least don't place it
before any #include lines.
From: Wolfgang Lorenz on
Hi Ike,

the purpose of the macro:

#define for if (1) for

is to make the loop counter local on Microsoft Visual C++ 5 from 1997.
Without it, this code would not compile:

for (int i = 0; i < 10; i++);
for (int i = 0; i < 10; i++);

Visual C++ 5 makes i to scope outside the for loop, and then the
second definition of i leads to a "variable already defined" error.
This behaviour has been changed in later versions of the compiler,
therfore the version check for _MSC_VER <= 1200.

You are right, it should not be defined before the #include <stdio.h>
line. In real programs, I use it as a part of a private include file
which is always included after the standard include files have been
included.


> 1) Apparently the #define foreach text is supposed to be the
> rest of the line followed by the next line; that means the
> newline at the end of the first line should be escaped with a
> backslash

Oops, this line break has been inserted by the news posting program.
It is a single line in the source file.


> 2) The text of this macro contains an opening brace, but not the
> matching closing brace ...
> 3) What is the purpose of the /##/ construct?

To mask out the rest of the line ;)

foreach (i, int, is) {
...
}

will be translated into:

for (int ii = ...) ... { // {
...
}

I know, it is dangerous, but I found no other way to keep the balance
between the braces.

> My compiler (gcc) does not accept it.

Sorry to hear that. I use mostly fast Visual C++ 5, sometimes slow
Visual C++ 2008 and very rarely Intel C++ 9.


> If I fix these problems (i.e. add the backslash, remove the spurious
> opening brace at the call sites, and remove the /##/) then the program
> compiles and seems to run okay.

Obviously, gcc does not have these safety checks like Visual C++ 2008.
But because /##/ does not work with gcc, there is no more balance
between the braces.


> My advice is to remove the ``for'' macro, or, at least don't place
> it before any #include lines.

This message translates into: "Throw away your old Visual C++ 5 from
1997 and use something newer!"

Well, maybe I would -- but it is fast, has everything I need, doesn't
go online when I press F1 -- and I paid for it when I was a
professional developer a long time ago. Today I don't even have a DSL
line, so there is no big file downloading.

My hope was that the template wizards know of another way which does
not depend on the uninitialized first parameter in the cast_to()
function.

--
Wolfgang
From: Ben Bacarisse on
Wolfgang Lorenz <wl924236(a)arcor.de> writes:
<snip>
>> 2) The text of this macro contains an opening brace, but not the
>> matching closing brace ...
>> 3) What is the purpose of the /##/ construct?
>
> To mask out the rest of the line ;)
>
> foreach (i, int, is) {
> ...
> }
>
> will be translated into:
>
> for (int ii = ...) ... { // {
> ...
> }
>
> I know, it is dangerous, but I found no other way to keep the balance
> between the braces.
>
>> My compiler (gcc) does not accept it.
>
> Sorry to hear that. I use mostly fast Visual C++ 5, sometimes slow
> Visual C++ 2008 and very rarely Intel C++ 9.

And I am sorry to hear that! So many compilers that don't get it
right even though the same rules have applied for many, many, years:
comments are removed before macros are expanded. Once macro expansion
has happened, no comments will be removed. This is the same in C and
C++ and it has been the rule in C for 20 years. I doubt there has
been a C++ standard that had a different rule, though I don't have
enough old versions to go and check the full history.

Of course, you might be asking for this non-standard behaviour
explicitly but that is also risky. Are you sure the non-standard
behaviour won't change in the future?

<snip>
--
Ben.