473,770 Members | 1,880 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Type-punning / casting problem

Dear Experts,

I need a function that takes a float, swaps its endianness (htonl) in
place, and returns a char* pointer to its first byte. This is one of a
family of functions that prepare different data types for passing to
another process.

I have got confused by the rules about what won't work, what will work,
and what might work, when casting. Specifically, I have an
implementation that works until I remove my debugging, at which point
the compiler seems to decide that it can optimise away the writes to the
bytes other than the first, or something like that. Here it is:

template <typename T>
inline const char* encode_arg(T& t); // linker error if you try to
// encode a type for which there
// is no implementation

// This one works:
template <>
inline const char* encode_pq_arg<i nt>(int& i) {
i = htonl(i);
return reinterpret_cas t<const char*>(&i);
}

// This one doesn't:
template <>
inline const char* encode_arg<floa t>(float& f) {
uint32_t* ptr = reinterpret_cas t<uint32_t*>(&f );
*ptr = htonl(*ptr);
const char* cptr = reinterpret_cas t<const char*>(ptr);
return cptr;
}
When I dump cptr[0] to cptr[3] before the return, it works. Without the
debug, it fails; it's obviously hard to see what ends up in the result
in that case, but it looks undefined.

So, is there some tweak that will make this work, and be certain to
work? Am I better off using a union, or is that even less defined?
Does anyone know what the rules actually are?
Many thanks,

Phil.
Sep 14 '07 #1
12 2135
Phil Endecott wrote:
Dear Experts,

I need a function that takes a float, swaps its endianness (htonl) in
place, and returns a char* pointer to its first byte. This is one of a
family of functions that prepare different data types for passing to
another process.

I have got confused by the rules about what won't work, what will work,
and what might work, when casting. Specifically, I have an
implementation that works until I remove my debugging, at which point
the compiler seems to decide that it can optimise away the writes to the
bytes other than the first, or something like that. Here it is:

template <typename T>
inline const char* encode_arg(T& t); // linker error if you try to
// encode a type for which there
// is no implementation

// This one works:
template <>
inline const char* encode_pq_arg<i nt>(int& i) {
Typo? ^^
i = htonl(i);
return reinterpret_cas t<const char*>(&i);
}
Did you intend the bytes of the passed value to be swapped?
// This one doesn't:
template <>
inline const char* encode_arg<floa t>(float& f) {
uint32_t* ptr = reinterpret_cas t<uint32_t*>(&f );
*ptr = htonl(*ptr);
const char* cptr = reinterpret_cas t<const char*>(ptr);
return cptr;
}
When I dump cptr[0] to cptr[3] before the return, it works. Without the
debug, it fails; it's obviously hard to see what ends up in the result
in that case, but it looks undefined.
What doesn't work?

--
Ian Collins.
Sep 14 '07 #2
Ian Collins wrote:
Phil Endecott wrote:
>Dear Experts,

I need a function that takes a float, swaps its endianness (htonl) in
place, and returns a char* pointer to its first byte. This is one of a
family of functions that prepare different data types for passing to
another process.

I have got confused by the rules about what won't work, what will work,
and what might work, when casting. Specifically, I have an
implementati on that works until I remove my debugging, at which point
the compiler seems to decide that it can optimise away the writes to the
bytes other than the first, or something like that. Here it is:

template <typename T>
inline const char* encode_arg(T& t); // linker error if you try to
// encode a type for which there
// is no implementation

// This one works:
template <>
inline const char* encode_pq_arg<i nt>(int& i) {

Typo? ^^
Yes, copy&pastism, sorry!
> i = htonl(i);
return reinterpret_cas t<const char*>(&i);
}
Did you intend the bytes of the passed value to be swapped?
Yes; the caller doesn't need the value any more, so I swap it in-place
rather than making a copy. If I made a copy then I would have to
allocate memory for it and free it later.
>// This one doesn't:
template <>
inline const char* encode_arg<floa t>(float& f) {
uint32_t* ptr = reinterpret_cas t<uint32_t*>(&f );
*ptr = htonl(*ptr);
const char* cptr = reinterpret_cas t<const char*>(ptr);
return cptr;
}
When I dump cptr[0] to cptr[3] before the return, it works. Without the
debug, it fails; it's obviously hard to see what ends up in the result
in that case, but it looks undefined.
What doesn't work?
The four bytes pointed to by the const char* that this function returns
eventually get sent to a socket, and I can observe them at the other
end. They are wrong, i.e. if I pass 2.0 then the value at the other end
might be 8.923461290e-44. There is some non-determinism in the values I
see, which makes me think that I'm looking at uninitialised memory
rather than a systematic corruption. My first thought was to add
somethng like this:

std::cout << "cptr[0] = " << static_cast<int >(cptr[0]) << ....etc for
[1] to [3] ... << "\n";

However, as soon as I add this (just before the return statement), it
works: the correct value is seen in the other process. My feeling is
that the cptr[n] expressions in the debugging tell the compiler that
these bytes are needed; when the debuging is not there, it thinks that
they are not used, and optimises them away. Can you think of any other
explanation?
Regards,

Phil.
Sep 15 '07 #3
Phil Endecott wrote:
[..]
The four bytes pointed to by the const char* that this function
returns eventually get sent to a socket, and I can observe them at
the other end. They are wrong, i.e. if I pass 2.0 then the value at
the other end might be 8.923461290e-44. There is some
non-determinism in the values I see, which makes me think that I'm
looking at uninitialised memory rather than a systematic corruption. My
first thought was to add somethng like this:

std::cout << "cptr[0] = " << static_cast<int >(cptr[0]) << ....etc for
[1] to [3] ... << "\n";

However, as soon as I add this (just before the return statement), it
works: the correct value is seen in the other process. My feeling is
that the cptr[n] expressions in the debugging tell the compiler that
these bytes are needed; when the debuging is not there, it thinks that
they are not used, and optimises them away. Can you think of any
other explanation?
Compilers are written by humans. Errare humanum est. Hence all
compilers have bugs, known and unknown. If you want to know whether
the bug you're encountering is known, contact the compiler writers.
If you just want a work-around, disable optimization for the small
module in which this function (these functions) is (are), and see if
it makes any difference. I've seen a significant improvement from
seemingly random behaviour with the HP and Sun compilers before, and
even <gasp!with Microsoft's VC++ compiler, if optimizations are
disabled locally.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Sep 15 '07 #4
On Sep 15, 5:26 pm, "Victor Bazarov" <v.Abaza...@com Acast.netwrote:
Phil Endecott wrote:
[..]
The four bytes pointed to by the const char* that this function
returns eventually get sent to a socket, and I can observe them at
the other end. They are wrong, i.e. if I pass 2.0 then the value at
the other end might be 8.923461290e-44. There is some
non-determinism in the values I see, which makes me think that I'm
looking at uninitialised memory rather than a systematic corruption. My
first thought was to add somethng like this:
std::cout << "cptr[0] = " << static_cast<int >(cptr[0]) << ....etc for
[1] to [3] ... << "\n";
However, as soon as I add this (just before the return statement), it
works: the correct value is seen in the other process. My feeling is
that the cptr[n] expressions in the debugging tell the compiler that
these bytes are needed; when the debuging is not there, it thinks that
they are not used, and optimises them away. Can you think of any
other explanation?

Compilers are written by humans. Errare humanum est. Hence all
compilers have bugs, known and unknown. If you want to know whether
the bug you're encountering is known, contact the compiler writers.
If you just want a work-around, disable optimization for the small
module in which this function (these functions) is (are), and see if
it makes any difference. I've seen a significant improvement from
seemingly random behaviour with the HP and Sun compilers before, and
even <gasp!with Microsoft's VC++ compiler, if optimizations are
disabled locally.
It looks like an auto optimization error.Maybe - as a result of
pointer algebra on small argument type - the enregisterd parameter is
copied to stack and operated upon ,and filled with rubish at
return(you are returning a pointer to the automatic variable).
can you write this:

union exg
{
float f;
char cl[sizeof(float)];
exg& IndianSwap();
};

exg e={value};
e.IndianSwap();

and leave the optimization to the compiler(I think modern compilers
can do fine on this special case)?

regards,
FM.

Sep 15 '07 #5
terminator wrote:
[..]
can you write this:

union exg
{
float f;
char cl[sizeof(float)];
exg& IndianSwap();
};

exg e={value};
e.IndianSwap();

and leave the optimization to the compiler(I think modern compilers
can do fine on this special case)?
Initialising (or assigning to) one part of a union and using another
has undefined behaviour. Or at least it used to. So, I'd stay away
from such code, it is definitely non-portable, although probably just
as reinterpret_cas t to an array of chars.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Sep 15 '07 #6
On Sep 15, 7:46 pm, terminator <farid.mehr...@ gmail.comwrote:
On Sep 15, 5:26 pm, "Victor Bazarov" <v.Abaza...@com Acast.netwrote:
Phil Endecott wrote:
[..]
The four bytes pointed to by the const char* that this function
returns eventually get sent to a socket, and I can observe them at
the other end. They are wrong, i.e. if I pass 2.0 then the value at
the other end might be 8.923461290e-44. There is some
non-determinism in the values I see, which makes me think that I'm
looking at uninitialised memory rather than a systematic corruption. My
first thought was to add somethng like this:
std::cout << "cptr[0] = " << static_cast<int >(cptr[0]) << ....etc for
[1] to [3] ... << "\n";
However, as soon as I add this (just before the return statement), it
works: the correct value is seen in the other process. My feeling is
that the cptr[n] expressions in the debugging tell the compiler that
these bytes are needed; when the debuging is not there, it thinks that
they are not used, and optimises them away. Can you think of any
other explanation?
Compilers are written by humans. Errare humanum est. Hence all
compilers have bugs, known and unknown. If you want to know whether
the bug you're encountering is known, contact the compiler writers.
If you just want a work-around, disable optimization for the small
module in which this function (these functions) is (are), and see if
it makes any difference. I've seen a significant improvement from
seemingly random behaviour with the HP and Sun compilers before, and
even <gasp!with Microsoft's VC++ compiler, if optimizations are
disabled locally.
It looks like an auto optimization error.Maybe - as a result of
pointer algebra on small argument type - the enregisterd parameter is
copied to stack and operated upon ,and filled with rubish at
return(you are returning a pointer to the automatic variable).
It's not a bug. The compiler is allowed to assume that a
variable is only modified/read through expressions of its type,
or through expressions of char or unsigned char type. The fact
that something is modified through an uint32_t* is irrelevant
when the compiler is optimizing accesses to a float, for
example.
can you write this:
union exg
{
float f;
char cl[sizeof(float)];
exg& IndianSwap();
};
exg e={value};
e.IndianSwap();
and leave the optimization to the compiler(I think modern
compilers can do fine on this special case)?
If "IndianSwap " accesses cl, then it's undefined behavior.

--
James Kanze (GABI Software) email:ja******* **@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientier ter Datenverarbeitu ng
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Sep 15 '07 #7
On Sep 15, 8:23 pm, "Victor Bazarov" <v.Abaza...@com Acast.netwrote:
terminator wrote:
[..]
can you write this:
union exg
{
float f;
char cl[sizeof(float)];
exg& IndianSwap();
};
exg e={value};
e.IndianSwap();
and leave the optimization to the compiler(I think modern compilers
can do fine on this special case)?
Initialising (or assigning to) one part of a union and using another
has undefined behaviour. Or at least it used to.
It still does, although some compilers may guarantee this as an
extension. (I think g++ does.)
So, I'd stay away
from such code, it is definitely non-portable, although probably just
as reinterpret_cas t to an array of chars.
reinterpret_cas t to an array of char's is probably OK. The
problem in the original code was assigning through the
uint32_t*; that's undefined behavior if, as was the case, the
pointer was the result of a reinterpret_cas t from a float*.

--
James Kanze (GABI Software) email:ja******* **@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientier ter Datenverarbeitu ng
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Sep 15 '07 #8
On Sep 14, 12:02 pm, Phil Endecott
<spam_from_usen et_0...@chezphi l.orgwrote:
Dear Experts,

I need a function that takes a float, swaps its endianness (htonl) in
place, and returns a char* pointer to its first byte. This is one of a
family of functions that prepare different data types for passing to
another process.

I have got confused by the rules about what won't work, what will work,
and what might work, when casting. Specifically, I have an
implementation that works until I remove my debugging, at which point
the compiler seems to decide that it can optimise away the writes to the
bytes other than the first, or something like that. Here it is:

template <typename T>
inline const char* encode_arg(T& t); // linker error if you try to
// encode a type for which there
// is no implementation

// This one works:
template <>
inline const char* encode_pq_arg<i nt>(int& i) {
i = htonl(i);
return reinterpret_cas t<const char*>(&i);

}

// This one doesn't:
template <>
inline const char* encode_arg<floa t>(float& f) {
uint32_t* ptr = reinterpret_cas t<uint32_t*>(&f );
*ptr = htonl(*ptr);
const char* cptr = reinterpret_cas t<const char*>(ptr);
return cptr;

}
And it shouldn't. The encode_arg() function is effectively returning a
pointer to a local variable (the parameter f). So the caller of
encode_arg() receives a pointer to an object that no longer exists;
and therefore the value of the bytes obtained by dereferencing the
returned pointer - could be anything.

Greg
Sep 16 '07 #9
Greg Herlihy wrote:
On Sep 14, 12:02 pm, Phil Endecott
<spam_from_usen et_0...@chezphi l.orgwrote:
>Dear Experts,

I need a function that takes a float, swaps its endianness (htonl) in
place, and returns a char* pointer to its first byte. This is one
of a family of functions that prepare different data types for
passing to another process.

I have got confused by the rules about what won't work, what will
work, and what might work, when casting. Specifically, I have an
implementati on that works until I remove my debugging, at which point
the compiler seems to decide that it can optimise away the writes to
the bytes other than the first, or something like that. Here it is:

template <typename T>
inline const char* encode_arg(T& t); // linker error if you try to
// encode a type for which
there // is no implementation

// This one works:
template <>
inline const char* encode_pq_arg<i nt>(int& i) {
i = htonl(i);
return reinterpret_cas t<const char*>(&i);

}

// This one doesn't:
template <>
inline const char* encode_arg<floa t>(float& f) {
uint32_t* ptr = reinterpret_cas t<uint32_t*>(&f );
*ptr = htonl(*ptr);
const char* cptr = reinterpret_cas t<const char*>(ptr);
return cptr;

}

And it shouldn't. The encode_arg() function is effectively returning a
pointer to a local variable (the parameter f).
A pointer to the argument 'f'? You mean the address of it? The arg
is a reference. The address of a reference is the address of the
referenced object. Nothing is destroyed. Please revise your analysis.
So the caller of
encode_arg() receives a pointer to an object that no longer exists;
and therefore the value of the bytes obtained by dereferencing the
returned pointer - could be anything.

Greg
V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Sep 16 '07 #10

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

Similar topics

3
510
by: dgaucher | last post by:
Hi, I want to consume a Web Service that returns a choice, but my C++ client always receives the same returned type. On the other hand, when I am using a Java client, it is working fine (of course, the generated proxy is not the same). When I am looking at the C++ generated code, it seems fine, but when I am executing the code, I always get the first choice type.
2
3305
by: Jason Cartwright | last post by:
I have an abstract base class and two derived classes that I want to serialize and deserialize with schema validation. When I serialize instances of the derived classes the XmlSerializer adds the xsi:type="DerivedClass" attribute and the Instance Namespace. When I attempt to validate the xml upon deserialization the XmlValidatingReader chokes on this attribute value. I can't seem to find a way around this. Any suggestions?
100
5300
by: E. Robert Tisdale | last post by:
What is an object? Where did this term come from? Does it have any relation to the objects in "object oriented programming"?
6
2692
by: S.Tobias | last post by:
I'm trying to understand how structure type completion works. # A structure or union type of unknown # content (as described in 6.7.2.3) is an incomplete type. It # is completed, for all declarations of that type, by ^^^ # declaring the same structure or union tag with its defining # content later in the same scope. ^^^^^ (6.2.5#23)
3
16490
by: Mike in Paradise | last post by:
I have an application that is being passed objects which could either be an instance or a Type in the case of a Static Class When you do the GetType on the object that was originally a Static class it gives you a type of "System.RuntimeType" as opposed to the orignal Static Class Typ How do you get access to what type the the Orginal Static Class type was from the RuntimeType?? //Eg Routine...... Object objects = new Object Class1...
1
8706
by: Rob Griffiths | last post by:
Can anyone explain to me the difference between an element type and a component type? In the java literature, arrays are said to have component types, whereas collections from the Collections Framework are said to have an element type. http://java.sun.com/docs/books/jls/second_edition/html/arrays.doc.html
3
2829
by: john | last post by:
Hi to All To demonstrate: public class MyBaseGenericClass<T> { } public class MyGenericClass1<T: MyBaseGenericClass<T> {
7
7818
by: Sky | last post by:
I have been looking for a more powerful version of GetType(string) that will find the Type no matter what, and will work even if only supplied "{TypeName}", not the full "{TypeName},{AssemblyName}" As far as I know yet -- hence this question -- there is no 'one solution fits all', but instead there are several parts that have to be put together to check. What I have so far is, and would like as much feedback as possible to ensure I've...
5
3174
by: JH | last post by:
Hi I found that a type/class are both a subclass and a instance of base type "object". It conflicts to my understanding that: 1.) a type/class object is created from class statement 2.) a instance is created by "calling" a class object.
3
17128
by: amanjsingh | last post by:
Hi, I am trying to implement Java Web Service using Apache Axis2 and Eclipse as a tool. I have created the basic code and deployed the service using various eclipse plugin but when I try to invoke the service using client stub, I get this error... Exception in thread "main" java.lang.Error: Unresolved compilation problems: org.apache cannot be resolved to a type org.apache cannot be resolved to a type org.apache cannot be resolved to a...
0
9617
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, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9454
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 effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10257
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, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10099
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 tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
10037
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
5354
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5482
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4007
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
2
3609
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

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.