#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    3
    Rep Power
    0

    A doubt in c program


    hey guys, i am studying c programming on my own with no ones help,
    i have a doubt i found difficult to find on net so i am asking.

    consider the program below:
    Code:
    #include<stdio.h>
    void main()
    {
    float a=1.3;
    printf("%d\n",a);
    }
    the output i am getting is 10 digit no., for example- -1034327859. which not the value of a nor its address in memory. (i know that i am declaring a as float and printing it as integer :)/> )
    so my question is that what no. is that technically ?
    thank you !
  2. #2
  3. Contributed User
    Devshed Specialist (4000 - 4499 posts)

    Join Date
    Jun 2005
    Posts
    4,403
    Rep Power
    1871
    Code:
    $ gcc -Wall -Wextra baz.c
    baz.c:2:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
    baz.c: In function ‘main’:
    baz.c:5:1: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’ [-Wformat]
    > so my question is that what no. is that technically ?
    Garbage.

    http://en.wikipedia.org/wiki/Single-...g-point_format
    If you work out the sign, mantissa and exponent of your float, and assign the relevant bits "as if it were an int", then you get what you see.

    But C doesn't require that every possible bit pattern is a valid integer, so it might also just crash and burn.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    3
    Rep Power
    0
    Originally Posted by salem
    Code:
    $ gcc -Wall -Wextra baz.c
    baz.c:2:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
    baz.c: In function ‘main’:
    baz.c:5:1: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘double’ [-Wformat]
    > so my question is that what no. is that technically ?
    Garbage.

    http://en.wikipedia.org/wiki/Single-...g-point_format
    If you work out the sign, mantissa and exponent of your float, and assign the relevant bits "as if it were an int", then you get what you see.

    But C doesn't require that every possible bit pattern is a valid integer, so it might also just crash and burn.
    Is that number a memory location ? or something else ?
    it must be some kind of pattern because the number it prints might not be random ?
  6. #4
  7. Contributed User
    Devshed Specialist (4000 - 4499 posts)

    Join Date
    Jun 2005
    Posts
    4,403
    Rep Power
    1871
    Oh there's a definite pattern all-right.
    It's more obvious if you print it in hex.

    Or better yet, print it in binary and pay attention to the link I posted.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper
  8. #5
  9. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,216
    Rep Power
    2222
    Originally Posted by jibran3492
    hey guys, i am studying c programming on my own with no ones help,
    i have a doubt i found difficult to find on net so i am asking.

    consider the program below:
    Code:
    #include<stdio.h>
    void main()
    {
    float a=1.3;
    printf("%d\n",a);
    }
    the output i am getting is 10 digit no., for example- -1034327859. which not the value of a nor its address in memory. (i know that i am declaring a as float and printing it as integer :)/> )
    so my question is that what no. is that technically ?
    thank you !
    Bits are bits. Bits have no inherent properties that make them floating-point or integer or character or pointer or machine instruction. The only thing that makes a bit part of a floating-point or integer or character or pointer or machine instruction is how the software uses it.

    You have created a memory location which you have told the program to treat as a float, but then you tell printf to treat it as a integer. That is a stupid thing to do. And then you say that you did it deliberately! Why would you do such a thing?

    Salem told you to see what the bit pattern of that float is and then how that bit pattern would be interpreted as an int. Why didn't you do that? That is where your answer lies, so why couldn't you bother to get that answer?

    As a float, 1.3 is stored as 0x3FA66666 . Interpreted as a 32-bit int (assuming that you are not using an ancient 16-bit compiler like Turbo C), that would be 1067869798. Please note that it is a positive value, whereas you reported a negative value, -1034327859. Why couldn't you be bothered to copy-and-paste the actual value you got instead of just making something up? Why are you feeding us with misinformation? Even if you are using a 16-bit compiler in which case that pattern it would be looking at would be the lower-order two bytes, 0x6666, the int value would be positive, 26214.

    Part of your program using bits is that it creates patterns of bits, patterns which have meaning. The patterns for integers is Two's Complement and the number of bits that integers consist of is important. The patterns for floating-points is IEEE 754. You need to study and learn those patterns and learn how to work with them.

    We cannot do that for you. Only you can do that for yourself. All we can do is point you in the right direction. You need to take that direction; we cannot take it for you.
  10. #6
  11. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    3
    Rep Power
    0
    Originally Posted by dwise1_aol
    Bits are bits.........

    As a float, 1.3 is stored as 0x3FA66666 . Interpreted as a 32-bit int (assuming that you are not using an ancient 16-bit compiler like Turbo C), that would be 1067869798. Please note that it is a positive value, whereas you reported a negative value, -1034327859. Why couldn't you be bothered to copy-and-paste the actual value you got instead of just making something up? Why are you feeding us with misinformation? Even if you are using a 16-bit compiler in which case that pattern it would be looking at would be the lower-order two bytes, 0x6666, the int value would be positive, 26214.......................
    i can understand what you said...thanks for the information 'dwise1_aol' i didnt got what salem said at first read.
    i am using codeblocks(32bit) for programming. the actuall value i am getting is -1073741824. I also tired converting 1.3 to floating and then to decimal and repeated same converting 1.3 to double and then to decimal... values didnt matched.
    well I am a newbee in C programming and also i am not a Computer Science student, these might be the reason i am asking such questions :chomp: . only out of curiosity i asked :cool: :cool:
  12. #7
  13. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,216
    Rep Power
    2222
    I get the same thing, which is odd.

    -1073741824 as a 32-bit int (sizeof = 4) in hex is 0xC0000000, whose bit pattern would be the same as for the float value, -2.0f. But 1.3f is most definitely 0x3FA66666. That misinterpretation of a is not what I would expect.

    I expanded a bit on your program to test exactly what is being stored in a:
    Code:
    #include<stdio.h>
    
    int main()
    {
        unsigned char *bp;
        float a=1.3f;
        int i = 42;
        
        printf("%d\n",a);
    
        // display the memory contents of a and the four bytes after it
        for (i=0, bp=(unsigned char*)&a; i<8; i++, bp++)
            printf(" %02X", *bp);
            
        // display the memory addresses    
        printf("\nAddr a = %p, bp = %p\n", &a, bp);        
    
        return 0;
    }
    When I ran that, I got:
    C:TEST>a
    -1073741824
    66 66 A6 3F 7C FF 22 00
    Addr a = 0022FF78, bp = 0022FF80

    C:TEST>
    Please bear in mind that since this is on an Intel machine, the bytes for a multi-byte value, such as for an int or float or pointer, are stored in reversed order with the least significant byte first. This order is called little-endian, while most significant byte first would be big-endian.

    a contains exactly what I had predicted, 0x3FA66666. The four bytes after it, 0x0022FF7C, is the pointer variable, bp. Please note that when we printed out the byte, 0x7C, bp was pointing to address 0x0022FF7C (8 plus 4 is 12, which is 0x0C).

    All I can think is that something happened to that value internal to printf. Maybe somebody else has an explanation.

    But the main point here is to use the proper conversion flags in printf.
  14. #8
  15. Contributed User
    Devshed Specialist (4000 - 4499 posts)

    Join Date
    Jun 2005
    Posts
    4,403
    Rep Power
    1871
    I seem to remember that a certain number of float parameters were always passed in the floating point registers. I had thought it only applied to normal functions (not variadic ones like printf).

    Using the /Fa switch (visual c++) to generate an assembler listing should show exactly what (if anything) is either pushed onto the stack, or passed in an FP register.

    If it turns out that nothing is in fact pushed when trying to pass a float to printf, then the %d will inevitably look in the wrong place, and this could quite easily be the saved bp.

    Lacking visual studio to test with, I'll have to ask someone else...
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper
  16. #9
  17. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,216
    Rep Power
    2222
    Here is the assembly listing for that call from MinGW gcc:
    Code:
    	.file	"jibran1.c"
    gcc2_compiled.:
    ___gnu_compiled_c:
    	.def	___main;	.scl	2;	.type	32;	.endef
    .text
    LC1:
    	.ascii "%d\12\0"
    LC2:
    	.ascii " %02X\0"
    LC3:
    	.ascii "\12Addr a = %p, bp = %p\12\0"
    	.align 4
    LC0:
    	.long 0x3fa66666
    	.align 4
    .globl _main
    	.def	_main;	.scl	2;	.type	32;	.endef
    _main:
    	pushl %ebp
    	movl %esp,%ebp
    	subl $40,%esp
    	call ___main
    	flds LC0
    	fstps -8(%ebp)
    	movl $42,-12(%ebp)
    	addl $-4,%esp
    	flds -8(%ebp)
    	subl $8,%esp
    	fstpl (%esp)
    	pushl $LC1
    	call _printf
    	addl $16,%esp
    	movl $0,-12(%ebp)
    	leal -8(%ebp),%eax
    	movl %eax,-4(%ebp)
    	.align 4
    L5:
    Unfortunately, I had never worked much with 80x86 assembly and then with Microsoft's syntax instead of with this syntax, which I believe is AT&T. Is that flds mnemonic what you are talking about?
  18. #10
  19. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,216
    Rep Power
    2222
    And here it is from Visual Studio 2008:
    Code:
     . . .
    
    CONST	SEGMENT
    ??_C@_03PMGGPEJJ@?$CFd?6?$AA@ DB '%d', 0aH, 00H		; `string'
    CONST	ENDS
    
     . . . 
    
    ;	COMDAT _main
    _TEXT	SEGMENT
    _i$ = -32						; size = 4
    _a$ = -20						; size = 4
    _bp$ = -8						; size = 4
    _main	PROC						; COMDAT
    ; Line 4
    	push	ebp
    	mov	ebp, esp
    	sub	esp, 228				; 000000e4H
    	push	ebx
    	push	esi
    	push	edi
    	lea	edi, DWORD PTR [ebp-228]
    	mov	ecx, 57					; 00000039H
    	mov	eax, -858993460				; ccccccccH
    	rep stosd
    ; Line 6
    	fld	DWORD PTR __real@3fa66666
    	fstp	DWORD PTR _a$[ebp]
    ; Line 7
    	mov	DWORD PTR _i$[ebp], 42			; 0000002aH
    ; Line 9
    	fld	DWORD PTR _a$[ebp]
    	mov	esi, esp
    	sub	esp, 8
    	fstp	QWORD PTR [esp]
    	push	OFFSET ??_C@_03PMGGPEJJ@?$CFd?6?$AA@
    	call	DWORD PTR __imp__printf
    	add	esp, 12					; 0000000cH
    	cmp	esi, esp
    	call	__RTC_CheckEsp
    ; Line 12
    	mov	DWORD PTR _i$[ebp], 0
    	lea	eax, DWORD PTR _a$[ebp]
    	mov	DWORD PTR _bp$[ebp], eax
    	jmp	SHORT $LN3@main
    $LN2@main:
    I seem to recall that instructions starting with f had to do with the floating-point processor. So then:
    fld == floating point load?
    fstp == store pointer, floating point?
    Last edited by dwise1_aol; August 21st, 2013 at 03:18 PM.
  20. #11
  21. Contributed User
    Devshed Specialist (4000 - 4499 posts)

    Join Date
    Jun 2005
    Posts
    4,403
    Rep Power
    1871
    Ah, that makes sense.

    In both cases, because float is a variadic argument, it is automatically promoted to double (8 bytes).
    These are the
    fstp QWORD PTR [esp]
    and
    fstpl (%esp)
    instructions respectively.

    What the %d will actually end up printing is the low word of the (now promoted to double) floating point value.

    Code:
    $ cat baz.c
    #include <stdio.h>
    
    int main()
    {
      float a = 1.3f;
      union {
        unsigned int l[sizeof(double)/sizeof(int)];
        double d;
      } x;
      int i;
      x.d = a;
      for ( i = 0 ; i < sizeof(double)/sizeof(int) ; i++ ) {
        printf("%d: %d %x\n", i, x.l[i], x.l[i] );
      }
      return 0;
    }
    $ gcc baz.c
    $ ./a.out 
    0: -1073741824 c0000000
    1: 1073007820 3ff4cccc
    Here you can see that the low word of the double is indeed 0xc0000000, following the float->double promotion in the assignment.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper
  22. #12
  23. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,216
    Rep Power
    2222
    Roger that.

    So to explain it for lurkers, 1.3 will be represented in one of two manners depending on whether it's float or double, as shown by the outputs of a couple utilities of mine:
    C:>d2hex 1.3
    1.30000000000000 = 3F F4 CC CC CC CC CC CD

    C:>f2hex 1.3
    1.300000 = 3F A6 66 66

    C:>
    If the lurker would read the formats of single and double precision floating-point IEEE 754 (float and double, respectively), he will find that their exponent fields differ in length, which also accounts for the differences in the mantissas.

    So then when the float, 0x3FA66666, gets converted to a double, first its exponent field and mantissa get converted and then the extra bits added to the end of the mantissa all get set to zero. Thus, while a double of 1.3 should be 0x3FF4CCCCCCCCCCCD, a converted float of 1.3f would become 0x3FF4CCCCC0000000. That is an 8-byte value which is stored in little-endian memory as { 00 00 00 C0 CC CC F4 3F }. When printf interprets that as a 32-bit int, a 4-byte value, it only sees this, { 00 00 00 C0 }, which is 0xC0000000, which in two's complement decimal is -1073741824.

    Simple, straight-forward, and perfectly logical. Now why didn't I think of that?

    PS

    I modified your program slightly to display all 8 bytes of the converted float:
    Code:
    #include <stdio.h>
    
    int main()
    {
      float a = 1.3f;
      union {
        unsigned char ch[sizeof(double)];
        double d;
      } x;
      int i;
      x.d = a;
      for ( i = 0 ; i < sizeof(double); i++ ) {
        printf(" %02x", x.ch[i] );
      }
      return 0;
    }
    And I got
    C:TEST>a
    00 00 00 c0 cc cc f4 3f
    C:TEST>
    Hence 1.3f converted to double is 0x3ff4ccccc0000000, as predicted.

    QED

IMN logo majestic logo threadwatch logo seochat tools logo