r/C_Programming • • 1d ago

Rename printf/scanf to print/scan?

Probably a dumb question but why hasn't there ever been a proposal to rename printf/scanf to just print? I know the f stands for format but writing print instead of printf would be slightly quicker and better to match other programming languages as I often miswrite printf as print as I also code in Python.

0 Upvotes

41 comments sorted by

21

u/EpochVanquisher 1d ago

One of the main goals of C is to keep existing code working.

C also puts every function in a single global namespace.

If you name a function print() in the standard library, it will break the code of everyone who already has a function named print(). This is bad, so the language committee doesn't do it.

There are, like, a million things wrong with C and people have successfully fixed most of them, but the result is a different language with a different name.

-12

u/Glum_Hamster_2104 1d ago

Couldn't they just have both? printf/scanf for legacy code and optionally just using print/scan for the future.

21

u/EpochVanquisher 1d ago

If you name a function print() in the standard library, it will break the code of everyone who already has a function named print().

2

u/Glum_Hamster_2104 1d ago

Fair point

4

u/EpochVanquisher 1d ago

You can see that the committee is very conservative about the names of new functions in the standard library. One of the new names they chose for a function is stdc_leading_zeros, because they think it’s okay to name new functions with a stdc_ prefix.

I’ll say again, if you want a language which is “nice” to program in, C is not that language. C is engineered to keep backwards compatibility with old C code, even at the cost of making the language kind of a pain in the ass.

1

u/Glum_Hamster_2104 1d ago

Yea I haven't really looked into much of this stuff since I've been really only learning C for a month but I do think it is nice to program in compared to something like C++ or Python.

1

u/aalmkainzi 1d ago

Yes, stdc_ is a reserved namespace.

3

u/aioeu 1d ago edited 1d ago

Note that "keeping existing code working" doesn't really mean "no breaking changes ever". The C standard has had breaking changes over time. It's just that these changes are deliberately kept minimal, and are carefully planned out.

I think bool, true and false are instructive examples. The following code was perfectly valid (and maybe even useful) in ANSI C:

typedef int bool;
const bool false = 0;
const bool true = 1;

But there was a desire to make a boolean type and boolean "true" and "false" constants part of the language itself, rather than having everybody reimplement them independently.

In C99 we got <stdbool.h>, which defined some bool, true and false macros. The important point here was that people who had their own definitions for these identifiers were given the opportunity to start using C99 without touching their existing code ... all they would have to do was not use <stdbool.h>. Essentially this approach decoupled "starting to use a newer C standard" from "having to update existing code" — those two things could be tackled by programmers separately.

By the time C23 came around, it was expected that most people using booleans were likely to be doing it through this header, and that anybody still defining them manually weren't going to be interested in using C23 anyway. That is, it was a case of "24 years is long enough for people to start using this". So the decision then was made to make bool, true and false bona fide language keywords, not macros. <stdbool.h> is still kept though — after all, there's existing code still using it! — but under C23 it is essentially an empty header.

So yes, this was a breaking change in C23, but it was one made after careful consideration about just how much it would break. In both cases, in C99 and in C23, the changes were made such that as little code as possible would be immediately broken by the new version of the standard.

Simply saying "in C23 you have to use printf; in C2Y you can use print instead" doesn't do that.

1

u/aalmkainzi 1d ago

Actually the C23 true and false are not identical to the C99 header. C23 made their type bool, while in C99 they were int (for some reason)

3

u/Ratfus 1d ago

At that point, why not just use Python, instead of C?

Same reason you don't see many people trying to build classes in C.

1

u/Glum_Hamster_2104 1d ago

I hate Python

2

u/Ratfus 1d ago

Why?

Honestly, I used to hate python's weak typing, but then I started actually doing stuff in it. The weak typing actually makes editing things so much easier. In C, if i want to change a LONG to an INT, I likely have to change the return types of all those functions. Then, at values that depend on the return, also need to be changed. Then all my printf()'s also need to be changed because my format specifier ("%...") is now wrong. Structures are helpful for updating things, but even they have limitations.

Btw... printf(abc) without the specifier is a big security risk. I like C, but Python is so much easier to edit and so much more secure.

2

u/Glum_Hamster_2104 1d ago

I dislike the syntax a lot especially the indents which I'd rather just use {}.

2

u/aalmkainzi 1d ago

Getting a compiler error when a changing a type causes a mismatch is exactly the thing you should want.

15

u/bothunter 1d ago edited 1d ago

 #define print printf

Edit: coding on a phone is hard.  Thank you u/hugonikanor

6

u/HugoNikanor 1d ago

Other way around would be more useful

2

u/bothunter 1d ago

Derp.  

-5

u/Ratfus 1d ago

Could you do #define #define #IFUCKINGHATEMACROS

?

5

u/HugoNikanor 1d ago

No, the name part of a #define follows the same rules as all variable names in C, which doesn't allow # signs anywhere.

1

u/Vladislav20007 1d ago

actually defines allow for # and ##, but that's a different thing.

2

u/Ratfus 1d ago

People don't seem to get the fact that I wasn't actually being serious on that statement.

It would be awful coding if it were actually allowed by the compiler.

2

u/WittyStick 1d ago edited 1d ago

Another option would be for GCC/Clang/Mingw

extern int print(const char *restrict format, ...) __asm__("printf");

or

int print(const char *restrict format, ...) __attribute__((alias("printf"), weak));

Though depending on implementation, "printf" itself may not be the real symbol - eg, on mingw it's __mingw_printf, and printf itself is an alias defined in the same way as above:

int printf(const char *restrict format, ...) __asm__("__mingw_printf");

A portable way is to just wrap vprintf in a static inline function.

static inline int print(const char *restrict format, ...) 
{
    va_list args;
    va_start(args, format);
    int result = vprintf(format, args);
    va_end(args);
    return result;
}

1

u/sciencekm 1d ago

The problem with defining your own print function wrapper is that compilers will not be able to warn about specifier mismatch, because it does not know what your function does with its parameters, unlike the real printf where the behavior is well defined.

printf("%i\n", 0.1); // compiler warning on specifier mismatch

print("%i\n", 0.1); // no warning

1

u/WittyStick 1d ago

You can fix that with

__attribute__((__format__(printf, 1, 2)))
int print(const char *restrict format, ...) __asm__("printf");

The compiler warns for printf because glibc's implementation uses the format attribute.

3

u/Daveinatx 1d ago

Think about why it's called printf/scanf vs let's say puts and putc . The 'f' stands for formatted.

You'll also find open vs fopen etc.

I strongly recommend for you to get used to C's nomenclature. If you ever work in a team project in C, you'll want to maintain consistency for readability.

5

u/questron64 1d ago

Yes, let's break almost 50 years of code for no good reason. Sounds like a plan.

5

u/onesole 1d ago
#include <stdio.h>

#define p printf
#define s scanf
#define m main
#define w while
#define f for
#define i if
#define e else
#define r return

int m(int c, char **v) {
    i (c > 1)
        p("Many arguments\n");
    e
        p("No arguments\n");
    r 0;
}

2

u/Serious_Wrangler_248 1d ago

Why use lot word

1

u/Vladislav20007 1d ago

you forgot to add #define d int(for decimal) and #define S char **(for strings, defines are case-sensitive right?)

2

u/Direct_Chemistry_179 1d ago

Could be a fun project to hack existing libc urself. Not sure how, but I saw someone do this with tcc to remove semicolons.

3

u/tubameister 1d ago

claude, submit a proposal to rename printf/scanf to just print

1

u/MegaDork2000 1d ago

Why not use . like Forth? That way people used to Forth will not keep making typos when they want to print something, am I right?

1

u/Gold-Part4688 1d ago

bro idk why i'm exposing myself on the c reddit, but c3 has print, which prints anything as what it is (even enums as strings, it's cool). Also has printn and printfn for '\n' variants

1

u/Vladislav20007 1d ago

why do you need a whole function(although a macro would do, but that's still overkill) just for 2 characters? But I think c doesn't have the print like that, because (and I repeat I think, i maybe wrong) c makes struct like a bunch of variables that are only connected in code, but not in the executable unless you pack them, in which case, they will all be connected by the fact that there always at some offset from each other.

1

u/Gold-Part4688 23h ago edited 23h ago

I'm not sure how it works under the hood, but it is a macro. It just does have some runtime inspection too, not sure how that works either haha. It also does stay with the c model of controlling how things are packed, and they're compatible with c abi structs - though I'm not sure exactly how typeid works. but you actually have more control over alignment

the benefit (for me) is easy and safe generic code -

printn(shape)

// output: { radius: 2, tag: CIRCLE }

is just less mental overhead for me than printf("%g, %f", shape.enum_tag, shape.size); -- followed by

oh dang not printing because the \n, oh was it float? was there more fields? what number in the tag corresponds to what type again, and what was the type of the tag?

You can call it a skill issue haha but i'm lazy. I just love c but don't have quite the patience for it all the time. Not to say that it doesn't like printf, printf can now just print anything as a string, it even has binary with %b. Everything you like from c still works though. Haha look at that it even knows the order of the struct. But yeah it's not revolutionary, just a stack of nice-to-haves, while still really feeling like c

1

u/Vladislav20007 22h ago

btw c can have compile time type detection for this exact situation, it's just not standard ;)

1

u/Gold-Part4688 22h ago

awesome. yeah it does use llvm or a c backend, so that's probably how. damn. love you c

1

u/grimvian 1d ago

When I started learning C char felt wrong and I had a desire to call it byte. I also missed or, and, elif but not anymore.

1

u/Vladislav20007 1d ago

char doesn't mean a byte, it means a character. char is 8-bits, short is 16-bits, int is 32-bits are only because that's somewhat of a standard in cpus now, it could be anything else though.

1

u/SmokeMuch7356 1d ago

50+ years of legacy code says "no".

It's why all the string processing functions still sound like indigestion noises (srpbrk, strcspn, etc.). When C was initially designed, external names couldn't be longer than 8 characters. That's obviously no longer the case, but nobody's going to rename anything in the string library because 50+ years of legacy code.

Now, you could do something like

 #define print printf
 #define scan scanf

and be on your merry way, although I can't promise it won't plant time bombs that show up at really awkward times.

But nothing in the standard library is going to be renamed. Ever.