printf: what exactly should 'h' be for 16-bit ints? - Page 1
Forum section: electronics / general

author: HwAoRrDk
author_rank: Super Contributor
timestamp: October 18, 2022, 02:49:42 pm
content: Due to the excessive size of my platform's standard library printf implementation, and being increasingly short on space, I'm writing my own very basic one.I'm unsure about what exactly to do with the 'h' length modifier for integer format specifiers (e.g. %u, %d, %x, etc.) when the native word size for my 8-bit platform is 16-bits - that is,int=uint16_t, andshort≡int.Now, according to the reference oncppreference.com, the 'h' length modifier denotes ashortvalue, and indeed my platform's standard library implementation of printf ignores 'h' (because it would cause no difference in behaviour toint). But I've also seen other printf implementations for 8-bit platforms that treat 'h' aschar. I suppose that would make sense if you interpret 'h' as meaning 'half', andcharis indeed 'half' ofint.What to do?

author: DavidAlfa
author_rank: Super Contributor
timestamp: October 18, 2022, 03:06:00 pm
content: Try sizeof(short) to see the size on your architecture?Ultimately check the compiler manual, it's usually there.For example, XC8 use the same values for 8 and 16bit integers.

author: HwAoRrDk
author_rank: Super Contributor
timestamp: October 18, 2022, 03:13:35 pm
content: Quote from: DavidAlfa on October 18, 2022, 03:06:00 pmI already know what sizeshortis. As I already said,sizeof(short)=sizeof(int)- both are 2 bytes.

author: DavidAlfa
author_rank: Super Contributor
timestamp: October 18, 2022, 03:16:00 pm
content: Anyways, %h must be very rare, never saw that, I think a lot of compilers only support %d, %u, then l, ll..

author: HwAoRrDk
author_rank: Super Contributor
timestamp: October 18, 2022, 05:16:18 pm
content: Hmm, I just remembered that with variadic functions (such as printf), all non-fixed integer arguments undergo integer promotion. So, everything that is smaller than anintgets promoted to that. Now I see why in my platform's standard library printf implementation, it ignores the 'h' length modifier, because it won't ever get passed anything that is smaller thanint.So why does the 'h' or 'hh' length modifiers even exist?

author: DavidAlfa
author_rank: Super Contributor
timestamp: October 18, 2022, 06:05:45 pm
content: Legacy, perhabs? From the times you would sell organs for 64K ram?

author: coppice
author_rank: Super Contributor
timestamp: October 18, 2022, 06:12:43 pm
content: Quote from: HwAoRrDk on October 18, 2022, 05:16:18 pmMost of the %<something> entries for printf control strings are a horrible historical mess. The standards now define things like PRIu16 to be used in those strings, so obtain portable results. They work, but they can make the string really long and clumsy to read."h" comes from the very first edition of K&R in the 1970s, to print a "short int". The snag is they never specified what a short int is, and it varies from platform to platform.

author: DavidAlfa
author_rank: Super Contributor
timestamp: October 18, 2022, 06:44:33 pm
content: I recall seeing a 24 bit "short long" type... But never the "%h"

author: TheCalligrapher
author_rank: Regular Contributor
timestamp: October 19, 2022, 08:29:56 am
content: Quote from: HwAoRrDk on October 18, 2022, 02:49:42 pmOK. Sounds fine so far.Quote from: HwAoRrDk on October 18, 2022, 02:49:42 pmThat would be non-conforming. `h` means short, period. A conforming C implementation is not allowed to implement 8-bit `short`. The minimum range for `short` is -32767...+32767, which means that it is 16-bit wide at least.

author: coppice
author_rank: Super Contributor
timestamp: October 19, 2022, 05:21:43 pm
content: Quote from: TheCalligrapher on October 19, 2022, 08:29:56 amThat depends on what you expect to conform with. If you go back to K&R, they didn't exclude a short from being 8 bits. They kept word lengths really vague, like they had looked at Pascal, and thought "let's be as messed up as that". There were numerous compilers for 8 bit machines in the past which implemented 8 bit short ints.

author: TheCalligrapher
author_rank: Regular Contributor
timestamp: October 19, 2022, 07:48:11 pm
content: Quote from: coppice on October 19, 2022, 05:21:43 pmBy default you always conform with the latest language standard. Conforming withg something else (K&R, C89/90, C++98, whatever) is perfectly fine, but has to be declrated clearly, loudly and and explicitly.Since the OP does not make a mention of a specific version of language spec, they are talking about C17.Quote from: coppice on October 19, 2022, 05:21:43 pm`printf` in K&R did not have such length specifiers as `h`. Since the OP is talking about `h`, it automatically means C99 or higher.

author: coppice
author_rank: Super Contributor
timestamp: October 19, 2022, 08:04:28 pm
content: Quote from: TheCalligrapher on October 19, 2022, 07:48:11 pmThat is a very strange concept. Old code doesn't go away when new specifications arise. New specifications which actually break existing things are a disgrace. A lesson the C++ people never learned, but which the C people have generally been very cognisent of.QuoteI just checked and you are right. K&R only defined h for scanf, not for printf. They don't seem to mention how they expect you to print a short int, although its easy to cast it to an int. In practice, I can't remember a printf function that didn't support h for both printf and scanf.

author: HwAoRrDk
author_rank: Super Contributor
timestamp: October 19, 2022, 08:40:38 pm
content: Quote from: TheCalligrapher on October 19, 2022, 07:48:11 pmYes, I am working with C17.Quote from: coppice on October 19, 2022, 08:04:28 pmTalking of scanf, after doing a bit more research, I came to the conclusion that the 'h' (and 'hh') length modifiers must only be useful for scanf, and their presence for printf is really only for 'symmetry' rather than anything useful (due to all printf integer varargs being cast to int at minimum).I have decided to ignore 'h' length modifiers in my implementation - it will get treated the same as int.Have managed to save over 900 bytes by cutting out the standard library implementation and using my own!

author: ejeffrey
author_rank: Super Contributor
timestamp: October 19, 2022, 11:06:26 pm
content: Quote from: HwAoRrDk on October 18, 2022, 02:49:42 pmTreating %h as short (keeping in mind the actual argument will be promoted to int or unsigned int) is the only compatible/conforming things to do. That said, since you are re-implementing printf from scratch because your library version is too bloated I assume your implementation will be non-conforming in several other ways. At that point who cares? Just name your function printfish and call it a day.

author: SiliconWizard
author_rank: Super Contributor
timestamp: October 19, 2022, 11:16:10 pm
content: Well of course. The OP is implementing their own version for their own use. Why would they even bother with odd format specifiers they may never have used and which add practically no value anyway?Were the OP commissioned to write a fully std-compliant printf, sure. But otherwise?Now if you want to treat integers as a specific width N, given that the rule is integer promotion, just pass the value modulo 2^N - if the actual parameter is wider than the format. If you pass a short and you want it displayed as a short, %d (or %u for unsigned) will work just fine. Only if you pass say an int (which *may* be wider than a short on a given platform) or a long and want to format it as a short, will you need to pass the modulo. Use the % operator rather than a bitwise mask in this case if the integer is signed to properly keep the sign.

author: golden_labels
author_rank: Super Contributor
timestamp: October 19, 2022, 11:32:25 pm
content: Quote from: HwAoRrDk on October 18, 2022, 02:49:42 pmprintfis a variadic function. Integers smaller thanintcan’t be passed to it.hlength modifier affects formatting, not argument type: it simply trims contents of theintpassed to whatshortcould represent.

author: TheCalligrapher
author_rank: Regular Contributor
timestamp: October 20, 2022, 03:30:41 am
content: Quote from: coppice on October 19, 2022, 08:04:28 pmUm... It is not the same thing.K&R defined `h` as a full-blown standaloneconversion specifier, i.e you were supposed to use it as `%h` in `scanf`.ANSI C abandoned `h` as a conversion specifier completely. There's no such thing as `%h` in standard C. Neither in `scanf` nor in `printf`. Niether in the first C89/90 nor in modern C. K&R's `%h` is gone for good.C99 introduced `h` in a very different role: as alength modifier, not as a standalone format specifier. Since C99 `h` is supposed to be used in conjunction with "real" format specifiers like `d` or `u`, e.g. `%hd`.So, the role `h` played in K&R is very different from the role it plays in C99 and later. The OP's question is about the latter.

author: Ed.Kloonk
author_rank: Super Contributor
timestamp: October 20, 2022, 06:24:46 am
content: This is why hybrid languages annoy me.The .0001% use case where C implementation is haywire and coders just crack the shits and reinvent the wheel instead of commenting the life out of the one bit of problematic code so that we can sort it out when it matters. Sorry. /rant

author: newbrain
author_rank: Super Contributor
timestamp: October 20, 2022, 08:22:53 am
content: Quote from: TheCalligrapher on October 20, 2022, 03:30:41 amMinor correction: as a length modifier, %h<<conversion specifier>>, is to my knowledge* already there in C90.What is actually new in C99 is the 'hh' length modifier.This makes sense, otherwise there would be no way to use a short integer in a scanf, removing useful functionality from K&R C.* Unfortunately, I only have copies of the standard starting from C99 - where 'h' is neither listed in the changes wrt C90, nor it is in the rationale.But I have K&R books, from the first edition, confirming h was a conversion specifier:QuoteFrom the second, ANSI, edition:Quote

author: TheCalligrapher
author_rank: Regular Contributor
timestamp: October 20, 2022, 04:29:56 pm
content: Quote from: newbrain on October 20, 2022, 08:22:53 amYes, you are right. Somehow I missed it. As a length modifier `h` is already present in C89/90 for both `printf` and `scanf`.