On Wed, May 24, 2017 at 2:33 PM, Eric Blake wrote:
> On 05/24/2017 07:00 AM, Carl Fredrik Forsberg wrote:
>> I am experiencing problems printing long int values under cygwin64 installed 
>> on a Windows 10 machine.
>>
>> Below is a test program followed by its output to demonstrate the problem. 
>> The program was initially written to demonstrate the output from lrint(), 
>> and developed further to demonstrate to myself how negative integers are 
>> tackled by printf type specifiers (e.g. %li, %ld etc).
>
> Are you compiling with -Wall, or even -Wformat?
>
>>
>> My understanding is that lrint() should return a long int. However I am 
>> unable to get printf to print the correct number. Instead its output is 
>> treated as an unsigned integer.
>> Any  help or hints would be much appreciated.
>>
>> Regards
>> Carl Fredrik
>>
>> #include <stdio.h>      /* printf */
>> #include <math.h>       /* lrint */
>>
>> int main ()
>> {
>>   char text[64];
>>   printf ( "int -2 = %i\n", -2 );
>>   printf ( "int -1 = %i\n", -1 );
>>   printf ( "int 0 = %i\n", 0 );
>>   printf ( "int 1 = %i\n", 1 );
>
> Okay so far.
>
>>   printf ( "long int -2 = %li\n", -2 );
>>   printf ( "long int -1 = %li\n", -1 );
>
> Both buggy.  You are passing an int through varargs, but then telling
> printf to grab a long int.  It may or may not work depending on ABI and
> stack sizes and what not, but gcc will warn you that it is bogus.
>
>>   printf ( "type cast -1 = %li\n", (long int)-1 );
>>   printf ( "type cast lrint(-1.0) = %li\n", (long int)lrint(-1.0) );
>>   printf ( "lrint(-1.0) = %li\n", lrint(-1.0) );
>>   printf ( "lrint(1.0) = %li\n", lrint(1.0) );
>
> Okay.
>
>>   printf ( "long int 0 = %li\n", 0 );
>>   printf ( "long int 1 = %li\n", 1 );
>>   sprintf( text,"long int -1 = %li", -1 );
>
> Buggy.
>
>>   printf ( "Via sprintf: %s\n", text);
>
> Okay (well, if you overlook the fact that text was populated in a buggy
> manner)
>
>>   printf ( "size of long int: %i\n", sizeof(long int));
>>   printf ( "size of int: %i\n", sizeof(int));
>
> Buggy.  size_t should be printed with %zi, not %i (since size_t and int
> are not necessarily the same type).
>
>>   return 0;
>> }
>>
>>
>> compiled by:
>> gcc lrint_test.c -o lrint_test.exe
>
> Missing -Wall.  Also, some platforms require the use of -lm to actually
> link with lrint() (cygwin does not, though).
>
>>
>> Output:
>>
>> int -2 = -2
>> int -1 = -1
>> int 0 = 0
>> int 1 = 1
>> long int -2 = 4294967294
>> long int -1 = 4294967295
>
> Evidence of your bugs.
>
>> type cast -1 = -1
>> type cast lrint(-1.0) = 4294967295
>
> Now that's an interesting one - it may be that cygwin1.dll actually has
> buggy behavior in lrint().  In the source code, cygwin/math/lrint.c is
> dropping down to assembly; it could very well be that the assembly code
> is incorrectly truncating things at 32 bits (where it is just fine for
> 32-bit Cygwin, but wrong for 64-bit):
>
> long lrint (double x)
> {
>   long retval = 0L;
> #if defined(_AMD64_) || defined(__x86_64__) || defined(_X86_) ||
> defined(__i386__)
>   __asm__ __volatile__ ("fistpl %0"  : "=m" (retval) : "t" (x) : "st");
> #elif defined(__arm__) || defined(_ARM_)
>     retval = __lrint_internal(x);
> #endif
>   return retval;
> }
>
> But I'm not an assembly coding expert, so perhaps someone else will spot
> the fix faster.

I took a look at this.  The code in Cygwin looks fine, I think.  But
the assembly is wrong:

000000018015cd40 <lrint>:
   18015cd40:   48 83 ec 28             sub    $0x28,%rsp
   18015cd44:   f2 0f 11 44 24 08       movsd  %xmm0,0x8(%rsp)
   18015cd4a:   dd 44 24 08             fldl   0x8(%rsp)
   18015cd4e:   db 5c 24 18             fistpl 0x18(%rsp)
   18015cd52:   48 8b 44 24 18          mov    0x18(%rsp),%rax
   18015cd57:   48 83 c4 28             add    $0x28,%rsp
   18015cd5b:   c3                      retq

That last `mov` should be a `movq`.  The result in $rsp+0x18 is
correct (I checked in gdb), but the `mov` truncates it.  Not sure if
that's a gcc bug or what.

Best,
Erik

--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple

Reply via email to