Jump to content



Photo

three questions


  • Please log in to reply
4 replies to this topic

#1 Terabojin

Terabojin

    Neowinian

  • Joined: 16-September 13
  • Location: California

Posted 13 November 2013 - 09:14

Okay, I've been going back to the basics trying to get a better understanding of what I'm doing.  So I have three questions.

 

why are compilers "happy" to compile something like i = MAX;?

how does the compiler know what max is?

how does this relate to compiler errors like "function definition not found, assuming external"?

 

what I understand is that because i is the variable assigned to max, and max is defined in stdio.h, the compiler will run it (of course with other code to go along with it).  correct?  however i'm not quite sure about the last question.  is it because the function definition isn't contained in stdio.h and it is wanting another library to be included for the function?  or is it that the person writing the code has not defined the parameters of the function?




#2 +Karl L.

Karl L.

    xorangekiller

  • Tech Issues Solved: 15
  • Joined: 24-January 09
  • Location: Virginia, USA
  • OS: Debian Testing

Posted 13 November 2013 - 11:08

why are compilers "happy" to compile something like i = MAX;? 
how does the compiler know what max is?

what I understand is that because i is the variable assigned to max, and max is defined in stdio.h, the compiler will run it (of course with other code to go along with it).  correct?

 
The compiler allows you to use "MAX" as long as it has a definition. While "MAX" is not defined in the C standard library, you could easily define it in your program. Typically definitions (and depending on who you ask, global constants) contain all capital letters and sometimes underscores. This convention makes them easy to distinguish. For example, the maximum number an unsigned integer can contain is defined in limits.h as UINT_MAX.

 

Definitions are a construct of the C preprocessor. Although they are a canonical part of the language, they do not translate into machine code like instructions, variables, and functions. They are merely for the programmer's convenience. Therefore if you define MAX to be 255, the compiler will replace every instance of MAX in your code with 255 when it is compiled. As a result, definitions are not limited by type like variables. You can just as easily assign a string to a definition as an integer or floating point number.

 

The following program demonstrates the basic use of definitions.

/* max.c */

#include <stdio.h> // printf()
#include <limits.h> // UINT_MAX

#define MAX 255
#define FLOAT 15.5f
#define STRING "Hello World"

int main( int argc, char * argv[] )
{
    unsigned int u = UINT_MAX;
    int d = MAX;
    double f = FLOAT;
    const char * s = STRING;
    
    printf( "%s => %u : %u\n", "UINT_MAX", u, UINT_MAX );
    printf( "%s => %d : %d\n", "MAX", d, MAX );
    printf( "%s => %f : %f\n", "FLOAT", f, FLOAT );
    printf( "%s => %s : %s\n", "STRING", s, STRING );
    
    return 0;
}
$ clang -o max max.c
$ ./max
UINT_MAX => 4294967295 : 4294967295
MAX => 255 : 255
FLOAT => 15.500000 : 15.500000
STRING => Hello World : Hello World

how does this relate to compiler errors like "function definition not found, assuming external"?

is it because the function definition isn't contained in stdio.h and it is wanting another library to be included for the function? or is it that the person writing the code has not defined the parameters of the function?

 

You will get a warning message like you are describing if you use a function in the standard library without including the appropriate header. For example, the following program and its associated compiler output demonstrates this quite nicely.

/* hello.c */

int main( int argc, char * argv[] )
{
    printf( "Hello World!\n" );
    return 0;
}
$ clang -o hello hello.c 
hello.c:4:5: warning: implicitly declaring library function 'printf' with type 'int (const char *, ...)'
    printf( "Hello World!\n" );
    ^
hello.c:4:5: note: please include the header <stdio.h> or explicitly provide a declaration for 'printf'
1 warning generated.

The only reason the compiler allows this (and merely issues a warning instead of an error) is because it knows the function you are calling is in the standard library. If you tried to call any other function without explicitly defining it first, the compiler would spit out an error instead of an innocuous warning. The following program demonstrates this by relying on libparted without including the appropriate headers.

/* disk.c */

int main( int argc, char * argv[] )
{
    PedDevice * dev;
    PedDisk * disk;
    PedDiskType * type;
    
    dev = ped_device_get( argv[1] );
    if( !dev ) goto error;
    
    disk = ped_disk_new( dev );
    if( !disk ) goto error_destroy_device;
    
    type = ped_disk_type_get( "msdos" );
    if( !type ) goto error_destroy_disk;
    
    ped_disk_destroy( disk );
    disk = ped_disk_new_fresh( dev, type );
    if( !disk ) goto error_destroy_device;
    
    if( !ped_disk_commit( disk ) ) goto error_destroy_disk;
    
    ped_disk_destroy( disk );
    ped_device_destroy( dev );
    return 0;
    
    error_destroy_disk:
    ped_disk_destroy( disk );
    
    error_destroy_device:
    ped_device_destroy( dev );
    
    error:
    return 1;
}
$ clang -o disk disk.c 
disk.c:5:5: error: use of undeclared identifier 'PedDevice'
    PedDevice * dev;
    ^
disk.c:5:17: error: use of undeclared identifier 'dev'
    PedDevice * dev;
                ^
disk.c:6:5: error: use of undeclared identifier 'PedDisk'
    PedDisk * disk;
    ^
disk.c:6:15: error: use of undeclared identifier 'disk'
    PedDisk * disk;
              ^
disk.c:7:5: error: use of undeclared identifier 'PedDiskType'
    PedDiskType * type;
    ^
disk.c:7:19: error: use of undeclared identifier 'type'
    PedDiskType * type;
                  ^
disk.c:9:5: error: use of undeclared identifier 'dev'
    dev = ped_device_get( argv[1] );
    ^
disk.c:9:11: warning: implicit declaration of function 'ped_device_get' is invalid in C99 [-Wimplicit-function-declaration]
    dev = ped_device_get( argv[1] );
          ^
disk.c:10:10: error: use of undeclared identifier 'dev'
    if( !dev ) goto error;
         ^
disk.c:12:5: error: use of undeclared identifier 'disk'
    disk = ped_disk_new( dev );
    ^
disk.c:12:12: warning: implicit declaration of function 'ped_disk_new' is invalid in C99 [-Wimplicit-function-declaration]
    disk = ped_disk_new( dev );
           ^
disk.c:12:26: error: use of undeclared identifier 'dev'
    disk = ped_disk_new( dev );
                         ^
disk.c:13:10: error: use of undeclared identifier 'disk'
    if( !disk ) goto error_destroy_device;
         ^
disk.c:15:5: error: use of undeclared identifier 'type'
    type = ped_disk_type_get( "msdos" );
    ^
disk.c:15:12: warning: implicit declaration of function 'ped_disk_type_get' is invalid in C99 [-Wimplicit-function-declaration]
    type = ped_disk_type_get( "msdos" );
           ^
disk.c:16:10: error: use of undeclared identifier 'type'
    if( !type ) goto error_destroy_disk;
         ^
disk.c:18:5: warning: implicit declaration of function 'ped_disk_destroy' is invalid in C99 [-Wimplicit-function-declaration]
    ped_disk_destroy( disk );
    ^
disk.c:18:23: error: use of undeclared identifier 'disk'
    ped_disk_destroy( disk );
                      ^
disk.c:19:5: error: use of undeclared identifier 'disk'
    disk = ped_disk_new_fresh( dev, type );
    ^
disk.c:19:12: warning: implicit declaration of function 'ped_disk_new_fresh' is invalid in C99 [-Wimplicit-function-declaration]
    disk = ped_disk_new_fresh( dev, type );
           ^
disk.c:19:32: error: use of undeclared identifier 'dev'
    disk = ped_disk_new_fresh( dev, type );
                               ^
disk.c:20:10: error: use of undeclared identifier 'disk'
    if( !disk ) goto error_destroy_device;
         ^
disk.c:22:10: warning: implicit declaration of function 'ped_disk_commit' is invalid in C99 [-Wimplicit-function-declaration]
    if( !ped_disk_commit( disk ) ) goto error_destroy_disk;
         ^
disk.c:22:27: error: use of undeclared identifier 'disk'
    if( !ped_disk_commit( disk ) ) goto error_destroy_disk;
                          ^
disk.c:24:23: error: use of undeclared identifier 'disk'
    ped_disk_destroy( disk );
                      ^
disk.c:25:5: warning: implicit declaration of function 'ped_device_destroy' is invalid in C99 [-Wimplicit-function-declaration]
    ped_device_destroy( dev );
    ^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
7 warnings and 20 errors generated.

If we include the libparted headers so its data structures and functions are defined, the program will compile but fail to link.

/* disk.c */

#include <parted/parted.h>

int main( int argc, char * argv[] )
{
    PedDevice * dev;
    PedDisk * disk;
    PedDiskType * type;
    
    dev = ped_device_get( argv[1] );
    if( !dev ) goto error;
    
    disk = ped_disk_new( dev );
    if( !disk ) goto error_destroy_device;
    
    type = ped_disk_type_get( "msdos" );
    if( !type ) goto error_destroy_disk;
    
    ped_disk_destroy( disk );
    disk = ped_disk_new_fresh( dev, type );
    if( !disk ) goto error_destroy_device;
    
    if( !ped_disk_commit( disk ) ) goto error_destroy_disk;
    
    ped_disk_destroy( disk );
    ped_device_destroy( dev );
    return 0;
    
    error_destroy_disk:
    ped_disk_destroy( disk );
    
    error_destroy_device:
    ped_device_destroy( dev );
    
    error:
    return 1;
}
$ clang -o disk disk.c 
/tmp/disk-OOLVGV.o: In function `main':
disk.c:(.text+0x1f): undefined reference to `ped_device_get'
disk.c:(.text+0x3f): undefined reference to `ped_disk_new'
disk.c:(.text+0x63): undefined reference to `ped_disk_type_get'
disk.c:(.text+0x83): undefined reference to `ped_disk_destroy'
disk.c:(.text+0x90): undefined reference to `ped_disk_new_fresh'
disk.c:(.text+0xb0): undefined reference to `ped_disk_commit'
disk.c:(.text+0xc9): undefined reference to `ped_disk_destroy'
disk.c:(.text+0xd2): undefined reference to `ped_device_destroy'
disk.c:(.text+0xe7): undefined reference to `ped_disk_destroy'
disk.c:(.text+0xf0): undefined reference to `ped_device_destroy'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

The program fails to link because not every function is implemented. Headers include only a prototype of each function, not the functions themselves. The compiler can work with the information provided in the headers alone because it only needs to know about each function's interface to generate an object file which leaves the address of each function not implemented in the file itself undefined. Therefore when the linker puts these object files together, it has to resolve the addresses that the compiler did not. In the case of the standard library, this is never a problem. The standard library is linked into your program by default. However any other library, like libparted, has to be explicitly linked in so the linker can resolve the addresses of the functions you used from it. Notice how the "undefined reference" errors in the previous example go away with no code changes when I link in libparted.

$ clang -l parted -o disk disk.c

Hopefully my explanation makes sense. If not, maybe someone else can do better. I expect Asik is to answer your question much more succinctly than me at the very least.



#3 Andre S.

Andre S.

    Asik

  • Tech Issues Solved: 6
  • Joined: 26-October 05

Posted 13 November 2013 - 21:05

Okay, I've been going back to the basics trying to get a better understanding of what I'm doing.  So I have three questions.

 

why are compilers "happy" to compile something like i = MAX;?

how does the compiler know what max is?

how does this relate to compiler errors like "function definition not found, assuming external"?

 

what I understand is that because i is the variable assigned to max, and max is defined in stdio.h, the compiler will run it (of course with other code to go along with it).  correct?  however i'm not quite sure about the last question.  is it because the function definition isn't contained in stdio.h and it is wanting another library to be included for the function?  or is it that the person writing the code has not defined the parameters of the function?

 

"function definition not found, assuming external" is probably not related to the assignment "i = MAX;" in your program, although without seeing your source code it's hard to tell what exactly is causing the issue. No function is being called there.

 

MAX is likely to be a C macro defined in one of the headers you #include at the top of your source file, something like:

#define MAX 255

What the compiler does is simply start by cut-pasting every instance of "MAX" in your source code with "255". This is a dumb find-and-replace job: it's called the preprocessor.

 

Then in a second pass, what the C compiler actually compiles is:

i = 255;

This is fine as long as 255 is implicitely convertible to the type of i.

 

You state "what I understand is that because i is the variable assigned to max, and max is defined in stdio.h, the compiler will run it (of course with other code to go along with it).  correct?" Incorrect: the compiler does not run code. The compiler compiles code, i.e. it translates your human-readable C text file into binary instructions that your CPU can understand. When your program actually runs, all your source code is gone, irrelevant; your CPU doesn't speak C and doesn't care about C. I hope this is clear to you; if you think the compiler runs your code you're going to have a lot of difficulty understanding how it works.



#4 +Majesticmerc

Majesticmerc

    Resident Idealist

  • Tech Issues Solved: 5
  • Joined: 24-August 05
  • Location: United Kingdom
  • OS: Arch Linux / Win 7
  • Phone: HTC One X

Posted 14 November 2013 - 00:29

Okay, I've been going back to the basics trying to get a better understanding of what I'm doing.  So I have three questions.
 
why are compilers "happy" to compile something like i = MAX;?
how does the compiler know what max is?
how does this relate to compiler errors like "function definition not found, assuming external"?
 
what I understand is that because i is the variable assigned to max, and max is defined in stdio.h, the compiler will run it (of course with other code to go along with it).  correct?  however i'm not quite sure about the last question.  is it because the function definition isn't contained in stdio.h and it is wanting another library to be included for the function?  or is it that the person writing the code has not defined the parameters of the function?


First off, kudos to you going back to get a better grasp. That shows a willingness to learn that will serve you well :). From what I've see of your activity on here you're progressing well to learning how to program. Keep it up!

I think your terminology is a bit off (like Asik said, your compiler doesn't "run" your code, it just turns it into machine code), but you've got the right idea.

In it's most basic form C (and C++), compilation has three parts:

  1. Pre-processing
  2. Compilation
  3. Linking

In pre-processing, all the instructions that start with a "#" are processed. I'm sure you've seen the "#include" preprocessor instruction. In the #include instruction, the preprocessor will insert the #include'd file at that point. So if you have "#include <cstdio>", the preprocessor will replace that line of code with the contents of the system's stdio.h file (in theory).

 

As xorangekiller points out: With your "MAX" assignment, it's likely that one of your included files, or even your own .c file, has a preprocessor instruction called "#define MAX 12345" or similar. That being the case, the preprocessor will replace every occurrence of "MAX" with "12345". Pretty much like a find/replace all. By the time your code starts compiling, there's no such thing as "MAX" because every occurrence in your code has been replaced with the value that MAX represents (e.g. 12345).

 

To answer your specific questions:

  1. why are compilers "happy" to compile something like i = MAX;?
    • Because MAX has been replaced by the preprocessor with whatever MAX is defined as (e.g. #define MAX 123)
  2. how does the compiler know what max is?
    • It will be defined somewhere. Either as a "const int MAX = 12345" or "#define MAX 12345"
  3. how does this relate to compiler errors like "function definition not found, assuming external"?
    • It doesn't as far as I know. As xorangekiller says, you're probably missing a #include somewhere for the function that is causing the error/warning.


#5 barneshoward

barneshoward

    Resident One Post Wonder

  • Joined: 18-November 13

Posted 18 November 2013 - 09:51

Thanks for sharing information,your information are very helpful for me and increase my knowledge.





Click here to login or here to register to remove this ad, it's free!