473,385 Members | 1,740 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

Invalid cast

Hi,
Can someone give me an explanation why the following code produces a
bug. I think it's related to the compiler and that the first line is
not OK. I have no pb with gcc 3.4 but the bug appeared with gcc 4.1.1
A* p = ...;
int l;
(char*&)p += l;
The right way is
p = reinterpret_cast<A*>(reinterpret_cast<char*>(p) + l);
Thanks
Fred

Feb 6 '07 #1
9 3142
* Frederic Mayot:
Hi,
Can someone give me an explanation why the following code produces a
bug. I think it's related to the compiler and that the first line is
not OK. I have no pb with gcc 3.4 but the bug appeared with gcc 4.1.1
A* p = ...;
int l;
(char*&)p += l;
The right way is
p = reinterpret_cast<A*>(reinterpret_cast<char*>(p) + l);
reinterpret_cast, or a C-style cast that resolves to reinterpret_cast,
is a sure way to introduce a bug.

Remove the casts (you'll probably have to fix other code) and chances
are you're removing the bug too.

Hope this helps.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Feb 6 '07 #2
JLS
On Feb 6, 11:56 am, "Alf P. Steinbach" <a...@start.nowrote:
* Frederic Mayot:
Hi,
Can someone give me an explanation why the following code produces a
bug. I think it's related to the compiler and that the first line is
not OK. I have no pb with gcc 3.4 but the bug appeared with gcc 4.1.1
A* p = ...;
int l;
(char*&)p += l;
The right way is
p = reinterpret_cast<A*>(reinterpret_cast<char*>(p) + l);

reinterpret_cast, or a C-style cast that resolves to reinterpret_cast,
is a sure way to introduce a bug.

Remove the casts (you'll probably have to fix other code) and chances
are you're removing the bug too.

Hope this helps.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
There is other strangeness here also.

We don't know if p is properly allocated, since that code wasn't
provided.
the variable l is not initialized, so the line p += l is going to do
something unexpected.

I don't believe that "the code produces a bug" or "the bug appeared
with gcc 4.1.1" are proper ways of phrasing it. "The code is buggy",
or "the bug was first noticed with gcc 4.1.1" would be more accurate.
Code cannot produce a bug. The bug is in the code itself, not a
product of the code.

Feb 6 '07 #3
Thanks a lot for correcting my English. Next time, I will explicitly
ask for a technical answer ;-)

In the code I gave, the memory area between p and (char*)p + l is
valid. Let's suppose that we have
char* c = new char[M]; // M l
A* p = reinterpret_cast<A*>(c);

I also forgot to tell that this kind of code is used in an allocator.
So please don't tell me that reinterpret_casts are not appropriate in
that case.

I just wondered why
(char*&)p += l;
could be differently compiled than
p = reinterpret_cast<A*>(reinterpret_cast<char*>(p) + l);

If you don't know, kindly avoid answers like "this is not defined in
the C++ standard"

(My message was also posted to gnu.gcc.help and gnu.g++.help)

Feb 6 '07 #4
* Frederic Mayot:
>
I just wondered why
(char*&)p += l;
could be differently compiled than
p = reinterpret_cast<A*>(reinterpret_cast<char*>(p) + l);
In the first case you're reinterpreting a reference to the pointer p.

In the second case you're reinterpreting pointer p's value.

Reinterpreting a value need not preserve the bitpattern, although a
preserved bitpattern (except for padding with zeroes) is somewhat
implicit in the word "reinterpret".

To be sure you have working code you need to hold the pointer value in a
char* or void* (or variations of char): other data pointer types may not
be sufficient to hold an arbitrary pointer value.

So, first copy the pointer value to char*, then increment (which is what
the second statement does, in practice).

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Feb 6 '07 #5
Frederic Mayot wrote:
...
I just wondered why
(char*&)p += l;
could be differently compiled than
p = reinterpret_cast<A*>(reinterpret_cast<char*>(p) + l);
...
Let's just take a different example first. Let's assume we are using a platform
with sizeof(float) == sizeof(int) and identical alignment requirements for both
types. Consider the following code

float f = 5.0;
int i1 = (int) f; // 1
int i2 = *(int*) &f; // 2

Take a close look at lines labeled 1 and 2. Both lines will be accepted by the
compiler (there are issues here from the very pedantic point of view, but let's
just assume that the compiler accepted both). But do you understand the
difference between the two?

In the line 1 we have a cast that converts a 'float' into an 'int'. The behavior
of this conversion is defined by the language. Variable 'i1' will be initialized
with value '5' and that does not depend on the implementation.

In the line 2 we are actually create a pointer of type 'float*' that points to
'f', forcefully convert it to type 'int*' (this is implementation-defined, but
let's assume that it still points to the same spot) and then dereference it as
if we have an 'int' object in memory occupied by 'f'. In other words, in this
case we just take the raw memory occupied by 'float f' and read it as an 'int'
object. What do you think the result of this is going to be? The truth is,
there's absolutely no way to predict it from the language point of view. The
physical representation of 'float' value '5.0' will normally have no relation to
the physical representation of 'int' value '5', so there's virtually no chance
that 'i2' will be initialized with '5'. In practice, if it doesn't crash, you
will see some what looks like garbage in 'i2'.

I'm saying all this in order to emphasize the difference between _converting_ an
object of one type to another type (which is what we have in the first case),
and _reinterpreting_ the raw memory occupied by an object of one type as an
object of another type (which is what we have in the second case). The former
makes perfect sense when defined by the language or implementation, while an
attempt to do the latter makes no sense at all in majority of cases.

Now, back to your code.

Expression '(char*&) p' is equivalent to '*(char*) &p', which attempts to do
pretty much the same thing as line 2 in my float-int example. It is nothing else
that an attempt to _reinterpret_ the memory occupied by 'p' as an object of type
'char*'. Object 'p' has type 'A*'. Physical representation of 'A*' has
absolutely no relation to the physical representation of 'char*'. Which means
that this reinterpretation attempt makes no sense for the very same reason line
2 in the my float-int example made no sense.

Expression 'p = (A*) ((char*) p + 1)' (rewritten for brevity) is something
completely different. It is similar to the line 1 in the my float-int example.
It actually converts an 'A*' value into an 'char*' value, performs the increment
and then converts it back to 'A*' type. These conversions are
implementation-defined but, assuming that your implementation defines them the
way you want it to, they produce meaningful results.

--
Best regards,
Andrey Tarasevich

Feb 6 '07 #6
Physical representation of 'A*' has absolutely no relation to the
physical representation of 'char*'

You mean that A* can be represented as a 64bits integer in little
endian and char* as a 32bits integer in big endian, for example?
Do you have an example of a compiler which would use different
representations for pointers???
What I don't understand is that some conversions will be needed in the
assembler code so that all pointers (addresses) would be represented
in the system specific representation. Is that right?

Feb 7 '07 #7
I tried to compile two codes with gcc/64bits -O2. I'm not sure my
example makes sense...

1) First snipped code
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
struct A {double c[4];};
A* p = reinterpret_cast<A*>(new char[sizeof(A)*2]);
(char*&)p += sizeof(A);
p->c[2] = 12.0;

main:
..LFB2:
subq $24, %rsp
..LCFI0:
movl $64, %edi
call _Znam
movabsq $4622945017495814144, %rdx
movq %rdx, 16(%rax)
xorl %eax, %eax
addq $24, %rsp
ret
%%%%%%%%%%%%%%%%%%%%%%%%%%%%

2) Second one
%%%%%%%%%%%%%%%%%%%%%%%%%%%%
struct A {double c[4];};
A* p = reinterpret_cast<A*>(new char[sizeof(A)*2]);
p = reinterpret_cast<A*>(reinterpret_cast<char*>(p) + sizeof(A));
p->c[2] = 12.0;

main:
..LFB2:
subq $8, %rsp
..LCFI0:
movl $64, %edi
call _Znam
movabsq $4622945017495814144, %rdx
movq %rdx, 48(%rax)
xorl %eax, %eax
addq $8, %rsp
ret
%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Here is the difference:
movq %rdx, 16(%rax) // with (char*&)p += sizeof(A);
movq %rdx, 48(%rax) // with
reinterpret_cast<A*>(reinterpret_cast<char*>(p) + sizeof(A));

The second assembler code is what I expect. Not the first.

Feb 7 '07 #8
JLS
On Feb 6, 1:38 pm, "Frederic Mayot" <f...@mayot.netwrote:
Thanks a lot for correcting my English. Next time, I will explicitly
ask for a technical answer ;-)

In the code I gave, the memory area between p and (char*)p + l is
valid. Let's suppose that we have
char* c = new char[M]; // M l
A* p = reinterpret_cast<A*>(c);

I also forgot to tell that this kind of code is used in an allocator.
So please don't tell me that reinterpret_casts are not appropriate in
that case.

I just wondered why
(char*&)p += l;
could be differently compiled than
p = reinterpret_cast<A*>(reinterpret_cast<char*>(p) + l);

If you don't know, kindly avoid answers like "this is not defined in
the C++ standard"

(My message was also posted to gnu.gcc.help and gnu.g++.help)
in the code you gave, "l" is an integer that is not initialized.
Sometimes it will have the value 0. Sometimes, 30,000. It is hard for
me to believe that you could know for a fact that "the memory area
between p and (char*)p + l is valid" for all possible values of "l".

My goal wasn't to correct your English, but I've run across a lot of
people who would phrase things the way you did, not because their
English was bad, but because their English betrayed a hidden bias that
the problem wasn't because of something buggy in their code, it was
the fault of the compiler or the language or an act of God.

As far as why the cast behaves differently, I find both examples
sufficiently obfuscating that my mind refuses to process the
information. I guess if I had to debug code like that, I would sit
down and figure out what the compiler was doing, but I would probably
rewrite the code so that it was understandable at the same time.

I'm not 100 percent sure why you expect the compiler to operate the
same. Without spending much thought on it, I would expect that

(char*)p += l;

to be roughly the same as
reinterpret_cast<char*>(p) + l

but you have that pesky little "&" in there.

Feb 7 '07 #9
Frederic Mayot wrote:
Physical representation of 'A*' has absolutely no relation to the
physical representation of 'char*'

You mean that A* can be represented as a 64bits integer in little
endian and char* as a 32bits integer in big endian, for example?
In theory - yes. The language specification imposes certain restrictions on
pointer representations, that require, for example, that 'char*' and 'void*'
pointers use identical representations. But in case of 'char*' and some 'A*'
(assuming that 'A' is neither 'char' nor 'void') there's no such requirement.
Do you have an example of a compiler which would use different
representations for pointers???
I don't know of any. Admittedly, this would be a rather exotic implementation.

In practice the code you used (meaning that '(char*&) p += 1' part) will work
"as expected" in many (or most) cases. This, BTW, brings the question: what is
it exactly that you referred to as a "bug" in your original message? What
exactly is the problem you had with '(char*&) p += 1'?
What I don't understand is that some conversions will be needed in the
assembler code so that all pointers (addresses) would be represented
in the system specific representation. Is that right?
Well, yes. With a few "but"s.

Firstly, in practice, when it comes to "plain" pointer types like 'int*',
'char*' or 'A*' it wouldn't make much sense for an implementation to blindly
insist on a representation that is significantly different from the
hardware-specific one. Normally, you won't see any conversions in the machine
code, simply becuase they are not necessary.

Secondly, still the representation might be different from the hardware-specific
one, assuming that the conversion you mention are simple or trivial. In fact,
many platforms are actually using such representations, even though it might not
be too noticeable at the first sight. For example, the current x86 platform is
based on segmented memory access model and its full hardware pointer is
represented by a 'selector:offset' pair. But most C++ implementations in that
platform stick to one-segment flat-memory model, meaning that just the 'offset'
pair is used as C++ pointer. Of course, this does not require any repetitive
"conversion" efforts from the compiler.

Thirdly, speaking of C++ pointers in general, some kinds of C++ pointers have no
hardware-specific counterparts, meaning that one should normally expect that
they will be represented as somethig not directly related to underlying
hardware. Take pointers-to-members for example. But that's a different story.

--
Best regards,
Andrey Tarasevich
Feb 7 '07 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: | last post by:
When I execute the following (with an OleDBDataAdapter), wanting to add a row to a visual foxpro table: myrow= datasetTarget.Tables(0).NewRow 'fill all columns here like.. row(i)= myvalue '...
3
by: Krung Saengpole | last post by:
Hi, I used SQL Server 2000 Personal Edition. I created a stored procedure having input parameters as smallint,tinyint,char,varchar and smalldatetime. When I executed it by Query Analyzer, it's...
0
by: Alan Z. Scharf | last post by:
Win Server 2003 VS.Net 2003 --------------- 1. I'm having the same problem below on all six of my pages with a datagrid item. 2. These pages all worked fine for months until problem started....
5
by: Nick Flandry | last post by:
I'm running into an Invalid Cast Exception on an ASP.NET application that runs fine in my development environment (Win2K server running IIS 5) and a test environment (also Win2K server running IIS...
3
by: John Howard | last post by:
Making the following call to a local MSAccess database works fine: Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs) Dim intRows As Integer Dim strSQL As String Dim ds As New...
1
by: Hifni Shahzard | last post by:
Hi, I got a stored procedure, where it returns a value. But if I execute it. It gives an error as "Invalid cast from System.Int32 to System.Byte.". To make clear how do I execute this, below I'm...
15
by: David | last post by:
Hi, I have built a web application that will be a very high profile application. We had tested it, demonstrated it and shown that it all works. On a dress rehearsal run through, it failed...
6
by: cs_hart | last post by:
I am getting an invalid cast exception - cast from string to type double is not valid. Dim curName As String Dim prevName As String = "" curName = CStr(rows.Item(i).Item(colSchName)) ' extract...
7
by: Chris Thunell | last post by:
I'm trying to loop through an exchange public folder contact list, get some information out of each item, and then put it into a vb.net datatable. I run though the code and all works fine until i...
7
by: chance | last post by:
Getting and error on this first line of code: //inspector phone theField = reader.GetString(20); builder.MoveToBookmark("inspector_phone"); builder.Write(theField); the first line is...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.