r/C_Programming • • 11h ago

Question Why not specifying what to include ?

Hi, sorry if there is English mistake, it's not my first language.

I found online that the #include is replaced by preprocessor by the whole file being included, and I wondered why C isn't made so we can specify only parts of the files to include (like `import { x, y, z } from "file"` in typescript) so the compiled file is lighter ?

8 Upvotes

25 comments sorted by

45

u/pfp-disciple 10h ago

C is much older, and its design is much more straightforward. The behavior you're describing could be crudely done with macros at compile time. See #ifdef. 

Modern linkers (and probably not so modern ones) will eliminate unused code, anyway. So, if a file is included that has functions a(), b(), c,(), and d() but only b() and d() are used, the final executable won't have the code for a() and c(). 

14

u/International_Hat178 10h ago

OK, thanks to you and all other comments who explained well

4

u/llynglas 9h ago

Yes, it adds to the compile time as more text to parse, but the space and execution speed is not impacted.

2

u/vcunat 4h ago

Yes, but it's good to note that the primary use of includes is to get declarations and not definitions (which live in a .c), so you normally get how to call functions but not the functions themselves. Of course there are common static inline cases, and you can "misuse" includes, etc.

1

u/pfp-disciple 27m ago

I wanted to say something about that, but couldn't word it as well as you did. Thanks!

9

u/SirCodedRed 10h ago

It’s also important to note that the final binary file only has the code you used and this is done by the linker.

8

u/SmokeMuch7356 8h ago

You're not importing code as such; you're just loading symbol and function declarations so that your code will compile.

For example, C requires functions to be declared before they can be used. IOW, if you write

int main( void )
{
  printf( "Hello, world\n" );
}

and try to build it, the compiler will complain that printf hasn't been declared.1 There has to be a declaration of printf somewhere before it's called:

int printf( const char * restrict, ... );

int main( void )
{
  printf( "Hello, world\n" );
}

stdio.h just contains the declarations for printf and scanf and other functions, not their actual implementations. It also contains typedefs for the FILE and fpos_t types, definitions for macros like NULL, etc.


  1. As of C99, anyway; for C89 and earlier it would just assume the function returned int.

2

u/Zirias_FreeBSD 6h ago

This, at least as long as header files are used in the way they were intended to be used.

Might want to explicitly add what this means for

[...] so the compiled file is lighter ?

When used correctly, the contents of header files don't add anything to the compiled file, as they are only needed during compilation. Whether (and if so, how much) code is added by using stuff declared in headers depends entirely on linking.

3

u/sciencekm 10h ago edited 7h ago

You normally only have declarations in the files that you have in #include. The code still has to come from libraries or other C files. You only link the libraries and C object files that you need.

8

u/questron64 10h ago

When you say import in many languages it imports all the code you request at runtime, which is quite expensive if you want all the code from a large module. However, in C an #include is not import. Generally it's used to introduce header files which are intended to be declarations only, and it's not expensive to have all those declarations for most header files. All the functions those declarations refer to get compiled elsewhere at compile time, not a run time like in many scripting languages.

Some large libraries to help you out, though, and split up their header files into smaller chunks and allow you to include them individually, which does help large projects compile a bit quicker. But import and include are fundamentally different things, don't think of them as equivalent.

2

u/torsten_dev 10h ago

The preprocessor is not smart.

The compiler needs to read the entire file anyway.

import {x, y, z} wouldn't make your binary smaller than Dead code elimination.

All the globals and functions without static will still need unique names for the linker. C doesn't mangle names, and it doesn't have namespaces.

import {x,y,z} only benefit I could see in C is telling you why you includes the header.

3

u/ReallyEvilRob 10h ago

Because that's not how they designed the preprocessor to work.

1

u/mcsuper5 5h ago

If you only need one or two simple functions, you can just include the prototype before it is called instead of including the header. I'm saying it can work for some functions. No guarantees it is safe even if it works. Standard headers may just indicate prototypes for some functions, but may define some macros usually used when calling the code

These days, loading several hundred lines that usually don't even need to be compiled isn't a big deal.

Since gcc allows you to tell it the code has already been preprocessed. (see "-fpreprocessed" in the gcc manual) (*.i files are treated as mostly preprocessed c.) You could use another method of preprocessing the code. I don't know how standard that is.

You can also call the preprocessor separately. man cpp.

You could use a custom preprocessor, but you'd probably need custom headers and want to automate the preprocessing. (If you do something like this, INCLUDE an explanation in your source of the tool chain and any/all needed files for the tool chain. Nothing like going back to project 15 years later and not remembering how it worked. Been there and done that!)

1

u/Liam_Mercier 10h ago

Historical reasons, complexity of adding module style imports, etc.

There is a system like this in C++ but that is an entirely different language. There is also a lot more of a benefit to reducing compilation times in a language like C++ where you have a lot of instantiations and abstractions, versus a language like C which generally has better compile times.

1

u/torsten_dev 10h ago

c++ modules exist, but I've only heard disgruntled rumblings about it from c++ folk though.

0

u/ComradeGibbon 7h ago

Well now wouldn't that be nice.

There isn't any reason that couldn't be added to the language except the C++ standards committee would have a melt down.

-10

u/kinchkun 10h ago

Because c is a boomer language and doesn't have a module system

5

u/vertigosol 10h ago

Only runs on like 90% of embedded devices worldwide 

1

u/Devatator_ 3h ago

Uh isn't that C++? My Arduino Uno and ESP32 both use C++ and looking around a bit ago it seemed like C++ was far more common for anything embedded

-6

u/kinchkun 10h ago

and?

2

u/vertigosol 9h ago

Shitty resource heavy languages are terrible for real programming on real devices. There is a reason c is still used 

0

u/kinchkun 9h ago

A module system doesn't make language resource heavy. But compiling the same headers over and over again does make the compilation slower

1

u/Maqi-X 7h ago

No, it isn't. C complication model allows more parallel compilation than many languages with module systems do (for example, rust). In rust you need to split your project into separate crates because modules cannot be compilated simultaneously for whatever reason. Unlike C++, C headers are lightweight and they don't slow down compilation, and if they do you're using them wrong. C has one of the fastest compile times anyway because of how simple language it is.

1

u/tobdomo 6h ago

You can't wait the extra 3 ms it takes to scan and parse a header as opposed to waiting 23 ms it takes to scan the module you want to pull a function from?

6

u/ReallyEvilRob 10h ago

It never needed one.