4

Quick question:

strlen[char*] works perfectly regardless whether I #include <string.h> or not

All I get from compiler is a warning about implicit declaration, but functionally it works as intended.

Why is that?

James Raitsev
  • 92,517
  • 154
  • 335
  • 470
  • I'm not sure but I think it's related to stdlib. Have you included stdlib.h? In general, what other libraries have you included? – elitalon Apr 27 '11 at 14:43
  • I once asked the same thing, but I'll let someone else answer. Another good question is why do you need `-lm` when you already included `math.h` in your program? – Mr. Shickadance Apr 27 '11 at 14:44
  • `-lm` links a library to your compiled program. `#include ` introduces a bunch of constants and function prototype *declarations* (not definitions) into your code. – Noufal Ibrahim Apr 27 '11 at 14:47

7 Answers7

6

When you invoke undefined behavior, one possible behavior is that the program behaves as you expected it to, one your system, and with the current version of libraries and system software you have installed. This does not mean it's okay to do this. Actually a correct C99 compiler should not allow implicit function declarations; it should give you an error.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • Is it undefined behavior to call a non-prototyped function with the exact argument types it's expecting? There are some embedded-system compilers which pass const-qualified pointers differently from unqualified pointers, but I don't think their behavior is standards-conforming. Certainly the compilers which didn't know about prototypes didn't distinguish between the const-qualified and non-const-qualified pointers. – supercat Apr 27 '11 at 15:07
  • 1
    The arguments are not the issue, the return types is. `strlen` returns `size_t`, not `int`. Furthermore, C99 no longer has the implicit return type of `int`. Calling undeclared functions (which is different from functions lacking prototypes - you're allowed to omit the arguments, but not the return type, in a declaration) is no longer legal. – R.. GitHub STOP HELPING ICE Apr 27 '11 at 15:35
  • @R: Where did the original poster say anything about using C99? Prior to C99, calling undeclared functions was legal but deprecated. I think you're correct in noting that returning an unsigned int when a signed int is expected would be UB (size_t could be larger than 'unsigned int', but may not be) but I'm unaware of any compilers that will do anything weird if the type is the same except for signedness, and the numerical result will fit in signed and unsigned types (I've seen a variety of behaviors when sizes differ, or if values outside the shared signed/unsigned range are returned). – supercat Apr 27 '11 at 17:29
  • As of 12 years ago, "C" means C99. If you're intentionally coding to an outdated version of the standard you should say so. Otherwise I agree it may technically not be UB. Since the type of `size_t` is implementation-defined, if the implementation defines it as `unsigned int`, then your code is merely non-portable but not invoking UB. On the other hand, if the implementation defines `size_t` as `unsigned long` or some other type, you're invoking UB. – R.. GitHub STOP HELPING ICE Apr 27 '11 at 17:51
  • I wouldn't say that in 1999, C meant C99. C99 compilers are not, and probably never will be, available for all platforms. Some features which are required for C99 compliance cannot be implemented practically on small microcontrollers. It would be nice if there were a somewhat "current" standard which was applicable to things like 8-bit embedded micros, since it's helpful for compilers to support stuff newer than C89. BTW, is the behavior defined if a function that's expected to return an int actually returns an unsigned int? – supercat Apr 27 '11 at 18:29
  • I believe so, as long as the result fits in `int`, but I'm not sure. – R.. GitHub STOP HELPING ICE Apr 27 '11 at 19:21
4

The function prototypes in C are not compulsory. They're useful indications to the compiler so that it can do type checking on types which are passed into them. When you don't include string.h, a default signature is assumed for the function which is why you get the warning.

Noufal Ibrahim
  • 71,383
  • 13
  • 135
  • 169
3

If a function is called without a prototype in scope, the compiler will generate code to call a function which accepts whatever types of parameters are passed and accept an integer result. If the parameters match those the function expects, and if the function returns its result in a way the calling code can handle(*), all will be well. The purpose of prototyping is to ensure that arguments get converted into expected types if possible, and that compilation will fail if they cannot be converted. For example, if a non-prototyped function expects an argument of type 'long' and one attempts to pass an 'int', any of the following may occur:

  1. The program may crash outright
  2. Things may work as expected
  3. The function may execute as though it were passed some arbitrary different parameter value
  4. The program may continue to run, but with arbitrary values corrupting any or all program variables.
  5. The computer may cause demons may fly out the programmer's nose

By contrast, if the function were prototyped, the compiler would be guaranteed to do whatever was necessary to convert the 'int' to a 'long' prior to calling the function.

When C was originally conceived, prototypes didn't exist, and the programmer was responsible for ensuring that all arguments were passed with the precise types expected. In practice, it's a real pain to ensure that all function arguments are always the exact proper types (e.g. when passing the value five to a function that expects a long, one must write it as either "5L" or "(long)5"). Realistically speaking, there's never(**) any reason to rely upon implicit argument types, except with variadic functions.

(*) Any of the things that can happen with incorrect parameter types can happen with incorrect return types, except when a function is expected to return 'int' and the actual return value of the function would fit in an 'int', the results are more likely to be correct than when incorrect parameter types are used.

(**) The only exceptions I can think of would be if one was programming for some really old hardware for which a prototype-aware compiler was unavailable, or if one was programming for a code-golf or similar competition. The latter I consider puzzle-solving rather than programming, and I'm unaware of any hardware people would be interested in using for which the former condition would apply.

supercat
  • 77,689
  • 9
  • 166
  • 211
1

Because it's declaration ie equal to so called 'default declaration'. Compiler expects any unknown function to return int and expect parameters as passed at the first time of function usage in code.

akashihi
  • 917
  • 2
  • 9
  • 19
1

Usually this is because another header file which you have included ALSO includes string.h. Obviously it is bad practice to assume that you don't need to include something just because something else does, but it is most likely responsible for this effect.

devrobf
  • 6,973
  • 2
  • 32
  • 46
0

I guessing it's because in C an int is the default data type returned from a function. Can you give a fuller code example.

AnthonyLambert
  • 8,768
  • 4
  • 37
  • 72
0

The function prototype is there in include files. So even if you don't include those files, a fixed prototype int function_name(); is written. Now the code of strlen() is there in the library files which are linked at run time, so the function gives correct output (only if it is the only function with a fixed prototype int function_name();).

Ryan Wersal
  • 3,210
  • 1
  • 20
  • 29
Aragorn
  • 107
  • 1
  • 1
  • 10