Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCC no error while linking functions

Tags:

c

gcc

linker

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?

like image 482
Kartik Anand Avatar asked Apr 03 '14 05:04

Kartik Anand


2 Answers

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;
}
like image 109
user3386109 Avatar answered Sep 18 '22 18:09

user3386109


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   
like image 35
Nish Avatar answered Sep 17 '22 18:09

Nish