- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
There's another bigger WTF. if CONFIG_STRING contains '%first' as an example, the program will probably crash or will print garbage, like 0.000000irst
Admin
TRWTF is C of course.
Admin
Most C compilers I used in the past just print the format string if there is no argument given (argc allows to check for the amount of it). But printf("This " FIRST " is bad %s", "boom"); would actually bad. In general, yeah, it's a bad idea to use printf because it's a legacy C method and especially if you just want to stream out text. puts was better legacy option or in c++ you just stream it to cout.
Admin
The is nothing wrong with C; at least it's not Oracle Java.
Admin
an embedded %s would be worse, unless the data picked up by the %f happens to correspond to something jolly like a signalling NaN.
Admin
Actually, if XYZ doesn't support compile-time concatenation of adjacent string literals, it's not a C compiler. The rest of its input language might resemble C, but merging adjacent string literals like that is a required part of the language, and has been for more than thirty years. It was already required when the ANSI released their standard for C in 1989, and the first release of GCC was in 1987, so it would have been highly unlikely for the scenario depicted by the comments to ever happen unless the developers picked up a defective compiler that they thought would be a C compiler, but wasn't.
Admin
It's also not much of a quirk, is it? There's no semantic ambiguity. And on a Pythonic "no surprises" equivalency, you get what you expect. The only thing missing is a concatenation operator, and since C doesn't allow concatenation between a literal string and anything other than a literal string or a pointer -- what with not having objects and thus inheritance of ToString() -- it's hard to see what extra goodiness you would get out of a concatenation operator.
It worries me when youngsters like Remy seem to ignore the fact that C has had a pretty iron-clad definition since, as you say, C89. If I found a "compiler" XYZ that did not, in fact, do something as simple and as clearly stipulated as this, I wouldn't write the alternative formatting. Instead, I would worry about what the hell else the "compiler" is going to get wrong, and complain to my manager and/or the vendor.
Admin
Correction. C does not allow concatenation between a literal string and a pointer. I'm getting rusty. (No pun intended, although possibly applicable.)
Admin
There were tons of C compilers that didn't not implement the standard fully in the pre-2000 days. In fact, a fully compliant compiler was an absolute rarity and I can't remember a single one I'd use (Turbo C, Borland C, MSC, Watcom ... all had special quirks to it).
Admin
Maybe they re-invented a C compiler? (but broken)
That would be a meta-WTF.
Admin
The VAXC compiler from DEC!
ha ha ha ha I kill myself. Seriously, there were days when I wanted to. At least the DECC compiler was pretty good, when it came out.
Admin
It might depend on what the actual CONFIG_STRING is.
1 Does it evaluate to "some config"? 2 Does it evaluate to a bare __some_config_str? Where somewhere else is const char *__some_config_str = "some config";
Concatenation doesn't work in the second case...
Admin
For double fun, the kind of definition of
CONFIG_STRING
might depend on what#define
s are set...Admin
Not only is it ISO C89, it's even specified behavior in pre-standard K&R C. 2nd edition of K&R mentions this on p.38 (I don't have a copy of the 1st edition handy, but it's highly unlikely it differs here). Every C compiler that's ever existed should support this behavior.
The only rational explanation I have for why this code didn't work for non-GCC compilers is if somehow CONFIG_STRING weren't defined as a string literal for those compilers (but was a string literal with GCC).
Admin
I've come across toolchains that aren't up to C89 yet in weirder corners of the embedded space. They're the exception, certainly, but if someone tells me they have a non-compliant C compiler, I won't argue with them.
Admin
True, but they all supported fusing adjacent string literals. Even the lightly crippled Microware C compiler that I had in 1985 or so, for OS9, supported that, and it couldn't compile structure assignment statements.
Admin
Well, if we are looking back here a goodie from my first C days: https://archive.org/details/AmigaCForAdvancedProgrammers/page/2/mode/2up Lattice was considered the most reliable standard conforming one, but oh boy, it was rough. You could nest macros only 16 times and then it simply stopped working for example :-) And edge cases like that was what I meant with quirks, random limitations from character limits, maximum amount of some sort of entities, maximum amount of nesting something etc.
Admin
I've used gcc and clang. I'm currently using clang and aside from emitting a warning when compiling
print("%d\n")
(more % conversions than data arguments), it does the dumb thing. When I ran a short program containing just that statement, it just printed a randomish number followed by a carriage return.There's no
argc
withprintf
, it determines the number of arguments by the number of format specifiers and it's not a compiler thing either:printf
is part of the C standard library and it wasn't necessarily compiled with the same C compiler. There's no way for it to tell it wasn't supplied with enough arguments in any particular case.No, this is just wrong.
puts
has no options for argument formatting. Admittedly, it would work for this particular use-case except that you've got to make sure the\n
is appended. The correctprintf
is superior IMO i.e.printf("%s\n", CONFIG_STRING);
Also, if you are programming in C, then by definition,cout
is not available to you: C != C++.Even if you are programming in C++, if you have arguments in strings, you definitely want to be using some equivalent of C format strings, unless you don't care about translating your program into other languages. C format strings are easier to translate into languages where words might have to come in a different order than IO stream expressions*.
Addendum 2023-01-10 13:22: The last line is meant to be the footnote but the editor swallowed the asterisk.
Also, referencing arguments out of order is POSIX functionality and it's not in the C standard.
Admin
Dare I try to use a quote and a code block with no preview? Yes!
While you are technically correct, printf is defined variadically and you can absolutely get the number of arguments using va_start() and friends.
Admin
It has occurred to me that printf format strings are a bit like leibnitzian notation in differential calculus: hard to justify theoretically but just too convenient in practice not to keep creeping back whenever some dogmatically purist authority tries to outlaw them.
Admin
Oh yeah, va_start, va_end, va_arg, va_list - I completely mixed it up with main(). My mistake, need to code more old school C again for fun.
My reply refers to the issue as a formatting string in context with printf (see original post).
Now that is a ton of overhead for a literal string and the worst option of all. First you have the format string parsing, then it has to skip the optimization part for strings without format arguments and finally depending on the implementation it calls sprintf() internal or does two IO calls (stdout) depending on the implementation.
In contract puts("configuration: " CONFIG_STRING "\n") in best case results in one string literal and one IO call for stdout.
Admin
Really? What speed difference have you measured?
Admin
puts
adds\n
itself.%
somewhere. Rewritting it in 3 calls "fixed" it by changing stack content. (the guess thatCONFIG_STRING
is not a literal on XYZ is more plausible, though)Admin
The real WTF is, that if you compile it neither on GCC nor on XYZ, it won't print anything.
For whom it may concern: the first edition of "The C Programming Language" by K&R does not mention string constant concatenation at all (the book doesn't mention it being the first or any edition, which probably means, it is the first).
Admin
is using printf when a fputs would work better
Admin
Well, it's some overhead. Unless, you're printing it a few thousand times a second, it's probably not significant.
OK, that would be fine as long as you are not overly concerned about localisation (for "configuration"). However, almost certainly, both this and the
printf
options will result in only one IO system call.Admin
Assuming this is not performance-critical code (and if it is performance-critical, why are you using printf), TRWTF is even bothering with the compile-time concatenation branch at all. It's just extra code that is not fully portable across all the (non-compliant) compilers you're using, so just drop that branch and use the portable solution.