6

I've the following two .c files

main.c

#include <stdio.h>

int print();
int show(int);

int main()
{
    int i = 0; 
    float x = 1.0;
    int y = *((int*)(&x));

    print();

    i = show(5);
    printf("%d", i);
    printf("\n%d", y);

    return 0;
}

foo.c

#include <stdio.h>

void print()
{
    printf("Hello World !!\n");
}

float show()
{
    return 1;
}

And here's is my makefile

CC = gcc
CFLAGS = -I. -Wall -pedantic -Wconversion

.PHONY: clean

%.o: %.c
    $(CC) -c -o $@ $< $(CFLAGS) 

main: main.o foo.o
    $(CC) -o main main.o foo.o $(CFLAGS)

clean:
    rm -rf *.o
    rm -rf main

Here's the output

Hello World !!
1065353216
1065353216

If I build the above, there is absolutely no error. It seems while linking gcc doesn't care that the two functions have different return types and different argument lists.

The second point is that in the function show instead of doing an implicit conversion from float to int, the bit patterns are getting copied, which I've verified using the second printf call.

Why is the above happening? I know this won't happen in g++ due to name mangling, but isn't this a serious problem?

8
  • 10
    Yes, the linker doesn't know about data types. That's why you should be using a header file to declare these functions. Commented Apr 3, 2014 at 5:23
  • @OliCharlesworth Ok but still why is there an implicit conversion not happening in show? Commented Apr 3, 2014 at 5:27
  • I'm not sure what you mean. You're returning a float, and then interpreting that return value as an int. Commented Apr 3, 2014 at 5:28
  • @OliCharlesworth I know I should use a header file. I was just experimenting to see as to what can go wrong. Commented Apr 3, 2014 at 5:28
  • 1
    Of course. But in your original code, the compiler doesn't know that you're doing something silly. It has no reason to generate a conversion. Commented Apr 3, 2014 at 5:36

2 Answers 2

3

The trick is to declare your functions in a header file (foo.h) and then include that header file in the source file (foo.c). Also include the header file in any source file (e.g. main.c) that calls the functions declared in foo.h.

Including foo.h in foo.c allows the compiler to verify that the function declarations match the function definitions. Including foo.h in main.c let's the compiler verify that main.c is using the functions correctly, and also allows the compiler to make any necessary type conversions.

Lying to the compiler, by falsely declaring the functions in main.c, does you no good, as you found out.

foo.h

void  print( void );
float show( void );

main.c

#include <stdio.h>
#include "foo.h"

int main()
{
    int i = 0; 

    print();

    i = show();
    printf("%d\n", i);

    return 0;
}

foo.c

#include <stdio.h>
#include "foo.h"

void print( void )
{
    printf("Hello World !!\n");
}

float show( void )
{
    return 2;
}
Sign up to request clarification or add additional context in comments.

5 Comments

Sure, but what if it's not lying to the compiler? What if you simply forget to change the h file while editing the c file? I think the OP has a right to be surprised that there is no warning whatsoever.
@MrLister That's the whole point. If you forget to change the .h file while editing the .c file, the compiler will catch the error provided that the .h file is included in the .c file. OP has no right to be surprised, because he declared the functions at the top of the main.c file, and not in the foo.h file where they belong.
Sorry, I missed that "include foo.h in foo.c" was the point you were making. My bad.
I know I should have made a header file.I was just experimenting with stuff.
Your question is a good one. It's important for new C programmers to understand how to use function prototypes correctly, and your question clearly demonstrates what can happen if the functions aren't properly declared in a header file.
1

implicit conversion will not happen as the code for main was generated using the signature on top declared. answer lies in disassembly. also output i got is "Hello World !! 1073741824 1065353216" which is diif from yours. Implicit conversion happens at compile time. Linking is not the time for linkers to add implicit conversion. both files are compiled with 2 diff signatures and they are compiled in their own domains not requiring any conversion.

Dump of assembler code for function main:

 0x0000000000400504 <+0>:     push   %rbp
   0x0000000000400505 <+1>:     mov    %rsp,%rbp
   0x0000000000400508 <+4>:     sub    $0x10,%rsp
   0x000000000040050c <+8>:     movl   $0x0,-0x8(%rbp)
   0x0000000000400513 <+15>:    mov    $0x3f800000,%eax
   0x0000000000400518 <+20>:    mov    %eax,-0xc(%rbp)
   0x000000000040051b <+23>:    lea    -0xc(%rbp),%rax
   0x000000000040051f <+27>:    mov    (%rax),%eax
   0x0000000000400521 <+29>:    mov    %eax,-0x4(%rbp)
   0x0000000000400524 <+32>:    mov    $0x0,%eax
   0x0000000000400529 <+37>:    callq  0x400570 <print>
   0x000000000040052e <+42>:    mov    $0x5,%edi
   0x0000000000400533 <+47>:    callq  0x400580 <show>
   0x0000000000400538 <+52>:    mov    %eax,-0x8(%rbp)
   0x000000000040053b <+55>:    mov    $0x400698,%eax
   0x0000000000400540 <+60>:    mov    -0x8(%rbp),%edx
   0x0000000000400543 <+63>:    mov    %edx,%esi
   0x0000000000400545 <+65>:    mov    %rax,%rdi
   0x0000000000400548 <+68>:    mov    $0x0,%eax
   0x000000000040054d <+73>:    callq  0x4003f0 <printf@plt>
   0x0000000000400552 <+78>:    mov    $0x40069b,%eax
   0x0000000000400557 <+83>:    mov    -0x4(%rbp),%edx
   0x000000000040055a <+86>:    mov    %edx,%esi
   0x000000000040055c <+88>:    mov    %rax,%rdi
   0x000000000040055f <+91>:    mov    $0x0,%eax
   0x0000000000400564 <+96>:    callq  0x4003f0 <printf@plt>
   0x0000000000400569 <+101>:   mov    $0x0,%eax
   0x000000000040056e <+106>:   leaveq 
   0x000000000040056f <+107>:   retq   

End of assembler dump. (gdb) disass show Dump of assembler code for function show:

   0x0000000000400580 <+0>:     push   %rbp
   0x0000000000400581 <+1>:     mov    %rsp,%rbp
   0x0000000000400584 <+4>:     mov    $0x40000000,%eax
   0x0000000000400589 <+9>:     mov    %eax,-0x4(%rbp)
   0x000000000040058c <+12>:    movss  -0x4(%rbp),%xmm0
   0x0000000000400591 <+17>:    leaveq 
   0x0000000000400592 <+18>:    retq   

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.