Comparing D vs C++ (wierd behaviour of C++)

Patrick Schluter Patrick.Schluter at bbox.fr
Tue Jul 24 15:03:07 UTC 2018


On Tuesday, 24 July 2018 at 14:08:26 UTC, Daniel Kozak wrote:
> I am not C++ expert so this seems wierd to me:
>
> #include <iostream>
> #include <string>
>
> using namespace std;
>
> int main(int argc, char **argv)
> {
> 	char c = 0xFF;
> 	std::string sData = {c,c,c,c};
> 	unsigned int i = (((((sData[0]&0xFF)*256
> 					+ (sData[1]&0xFF))*256)
> 					+ (sData[2]&0xFF))*256
> 					+ (sData[3]&0xFF));
> 					
> 	if (i != 0xFFFFFFFF) { // it is true why?
> 		// this print 18446744073709551615 wow
> 		std::cout << "WTF: " << i  << std::endl;
> 	}	    	
> 	return 0;
> }
>
> compiled with:
> g++ -O2 -Wall  -o "test" "test.cxx"
> when compiled with -O0 it works as expected
>
> Vs. D:
>
> import std.stdio;
>
> void main(string[] args)
> {
> 	char c = 0xFF;
> 	string sData = [c,c,c,c];
> 	uint i = (((((sData[0]&0xFF)*256
> 					+ (sData[1]&0xFF))*256)
> 					+ (sData[2]&0xFF))*256
> 					+ (sData[3]&0xFF));
> 	if (i != 0xFFFFFFFF) { // is false - make sense
> 		writefln("WTF: %d", i);
> 	}			
> }

int promotion rule. char is signed. The 256 are signed. When the 
result goes above INT_MAX it overflows (i.e. we're in UB 
territory) and the result can be anything. The registers of the 
CPUs are 64 bit wide so it sign extends the calculation and as 
the optimization removes the truncating memory write and reload, 
the value of the complete register is then printed by the cout>>.

Conclusion: typical C(++) undefined behavior due to signed value 
overflow.
Fix: 256u
and always compile with -ftrapv . In your case it would have 
catched the overflow.

In D, signed overflow is not UB so everything works as planned.

>
> compiled with:
> dmd -release -inline -boundscheck=off -w -of"test" "test.d"
>
> So it is code gen bug on c++ side, or there is something wrong 
> with that code.




More information about the Digitalmars-d mailing list