Path: csiph.com!feeder.erje.net!2.eu.feeder.erje.net!eternal-september.org!feeder.eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c Subject: Re: Updating pointer with result of sprintf Date: Tue, 28 Nov 2017 09:24:48 -0800 Organization: None to speak of Lines: 74 Message-ID: References: <87o9nmmzet.fsf@bsb.me.uk> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader02.eternal-september.org; posting-host="0a617e3b507af251ad64dcde7ced884b"; logging-data="30381"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18uPkqY4xWjpsogURjLtf+n" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) Cancel-Lock: sha1:ypfYz56nkzHucm2AkZPa6FU4Mi8= sha1:pUfxEq7IogVgYrpdDSXFPUPrsoo= Xref: csiph.com comp.lang.c:123577 Spiros Bousbouras writes: > On Tue, 28 Nov 2017 11:10:50 +0000 > Ben Bacarisse wrote: >> Noob writes: >> >> > Consider the following code: >> > >> > unsigned char src[32]; /* initialized somewhere */ >> > char buf[65]; >> > >> > for (i = 0; i < sizeof src; ++i) >> > buf += sprintf(buf, "%02x", src[i]); >> > >> > I think the above code has well-defined behavior, >> >> That should not compile because you can't assign to an array (buf). I >> think you have miss-transcribed the code. You probably have a pointer >> to the buffer like this: >> >> char buf[sizeof src + 1], *bp = buf; > > The size expression should be 2 * (sizeof src) + 1 . > >> for (size_t i = 0; i < sizeof src; i++) >> bp += sprintf(bp, "%02x", src[i]); >> >> Note that you can remove the mysterious 65 from the code. >> >> > but I have >> > a small doubt about modifying buf which is also an argument >> > to sprintf. IIUC, there is a sequence point *after* the function >> > call, so all should be well? >> >> There are sequence points before and after a function call. Mind you, >> given the nature of the code you could just write >> >> sprintf(buf + 2*i, "%02x", src[i]); >> >> That implicitly assumes that 2 bytes get written per call but then so >> does the size calculation for buf. > > And such an assumption is *** dangerous *** .There's no guarantee that > the maximum value for src[i] is 0xFF .The %02x directive does not > truncate the output , if it needs more than 2 characters to write the > full number then it will write more than 2 ; in which case the writing > will proceed beyond the end of the buffer and SHTF. So either the code > should use snprintf() or be written as src[i] is of type unsigned char. If CHAR_BIT==8, then its value cannot exceed 0xFF. The value is promoted to type int, but the value will be non-negative so using "%02x", (which expects an argument of type unsigned int) should be ok. I might cast the argument to unsigned: sprintf(buf + 2*i, "%02x", (unsigned) src[i]); just so I don't have to think about implicit promotion. If CHAR_BIT>8, then there is a possibility of undefined behavior. I might consider adding: #if CHAR_BIT != 8 #error "..." #endif (The code I work on at $JOB will almost certainly never run on anything with CHAR_BIT > 8, so in that context I wouldn't bother.) [...] -- Keith Thompson (The_Other_Keith) kst-u@mib.org Working, but not speaking, for JetHead Development, Inc. "We must do something. This is something. Therefore, we must do this." -- Antony Jay and Jonathan Lynn, "Yes Minister"