Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ strict-aliasing agnostic cast

I've read lots of QAs about strict aliasing here in Stack Overflow but all they are pretty common and discussion always tends to refer to deep-deep details of C++ standard which are almost always are difficult to understand properly. Especially when standard do not say things directly but describes something in a muddy unclear way. So, my question is probably a possible duplicate of tonns of QAs here, but, please, just answer a specific question:

Is it a correct way to do a "nonalias_cast"?:

template<class OUT, class IN>
inline auto nonalias_cast(IN *data) {
    char *tmp = reinterpret_cast<char *>(data);
    return reinterpret_cast<OUT>(tmp);
}

float f = 3.14;
unsigned *u = nonalias_cast<unsigned *>(&f);
*u = 0x3f800000;
// now f should be equal 1.0

I guess the answer is no. But is there any nice workaround? Except disabling strict-aliasing flag of course. Union is not a handy option as well unless there is a way to fit a union hack inside nonalias_cast function body. memcpy is not an option here as well - data change should be synchronysed.

An impossible dream or an elusive reality?

UPD:

Okay, since we've got a negative answer on "is it possible?" question, I'd like to ask you an extra-question which do bothers me:

How would you resolve this task? I mean there is a plenty of practical tasks which more-less demand a "play with a bits" approach. For instance assume you have to write a IEEE-754 Floating Point Converter like this. I'm more concerned with the practical side of the question: how to have a workaround to reach the goal? In a least "pain in @#$" way.

like image 362
Nikolai Shalakin Avatar asked Oct 09 '17 10:10

Nikolai Shalakin


People also ask

Does C have strict aliasing?

(OR Type Punning, Undefined Behavior and Alignment, Oh My!)In both C and C++ the standard specifies which expression types are allowed to alias which types. The compiler and optimizer are allowed to assume we follow the aliasing rules strictly, hence the term strict aliasing rule.

What is a type Punned pointer?

A form of pointer aliasing where two pointers and refer to the same location in memory but represent that location as different types. The compiler will treat both "puns" as unrelated pointers. Type punning has the potential to cause dependency problems for any data accessed through both pointers.

What is aliasing in PPL?

Aliasing: Aliasing refers to the situation where the same memory location can be accessed using different names. For Example, if a function takes two pointers A and B which have the same value, then the name A[0] aliases the name B[0] i.e., we say the pointers A and B alias each other.


1 Answers

As the other answers have correctly pointed out: This is not possible as you are not allowed to access the float object through an unsigned pointer and there is no cast that will remove that rule.

So how do you work around this issue? Don't access the object through an unsigned pointer! Use a float* or char* for passing the object around, as those are the only pointer types that are allowed under strict aliasing. Then when you actually need to access the object under unsigned semantics, you do a memcpy from the float* to a local unsigned (and memcpy back once you are done). Your compiler will be smart enough to generate efficient code for this.

Note that this means that you will have float* everywhere on your interfaces instead of unsigned*. And that is exactly what makes this work: The type system is aware of the correct data types at all times. Things only start to crumble if you try to smuggle a float through the type system as an unsigned*, which you'll hopefully agree is kind of a fishy idea in the first place.

like image 104
ComicSansMS Avatar answered Sep 25 '22 21:09

ComicSansMS