0

I have this weird problem where I am using sprintf and it puts FF in front of the value I have.

(e.g.) I should get 01, but I am getting FF01

My code looks like this

while(1)
{

    if(getkey()=='g')
    {
       sprintf(str_2, "%X", ~OWReadByte());
       lcd_delay();
       lcd_string(str_2);
    }
}

I did some checking on the LEDs and on there i get the value i want, after using sprintf it just gets screwed up.

s3v3ns
  • 198
  • 1
  • 17
  • What values do `str_2` and `i` have? – user694733 Jan 21 '15 at 11:14
  • 1
    What is the return type of `OWReadByte()`? Hint: the `%02X` format specifier means that you print a *minimum* of two hexadecimal digits, *not* a maximum. – jamesdlin Jan 21 '15 at 11:18
  • str_2 has a value of 8 and the value from OWReadByte is 8 bits long Int. I removed the i*2 – s3v3ns Jan 21 '15 at 11:24
  • 5
    Should `sprintf(str_2, "X", ~OWReadByte());` be `sprintf(str_2, "%X", ~OWReadByte());` – Santosh A Jan 21 '15 at 11:38
  • *"the value from `OWReadByte` is 8 bits long Int"*. Do you mean "8-bit `long Int`" or "8-bit long `Int`"? Please show the declaration of `OWReadByte`. Either way, it is not a `char` type so @mafso is correct. `~0xFE = 0xFF01` – Weather Vane Jan 21 '15 at 11:43
  • It is just int, sorry for the confusion, as proof int OWReadByte(void) – s3v3ns Jan 21 '15 at 11:46
  • In that case please understand and accept the answer - you have to mask off the unwanted bits. – Weather Vane Jan 21 '15 at 11:46
  • Do you want the "*one byte*" to be signed of unsigned? This is: do you want it to represent the values `0..255` or `-127..127`? – alk Jan 21 '15 at 11:51
  • So i tried masking like this `sprintf(str_2, "%X", (~OWReadByte()&0xFF));` But, i am losing zeroes now. – s3v3ns Jan 21 '15 at 11:55
  • 1
    @s3v3ns: For the zeros, you need a minimum field width of 2 and the `0` flag (to pad with 0 instead of spaces): "%02X" ;) – mafso Jan 21 '15 at 11:56
  • That made it work, thanks. There is this 1 thing tho, but this is probably from my functions. From the example program that i have, i can see that the hexes are printed other way around (e.g.) i have B3 D4 DC 07 00 00 example has 00 00 07 DC D4 B3 – s3v3ns Jan 21 '15 at 11:59
  • 1
    That looks like an [endianness](https://en.wikipedia.org/wiki/Endianness) issue. A value and its representation are really two things. Anyway, that's a different question. – mafso Jan 21 '15 at 12:07

2 Answers2

2

The unary ~ operator changes the bits of the whole int, not only the lower 8 bits. ~0xfeu (equivalently, ~0x00feu) is 0xff01u for 16-bit int.

I suggest to always use unsigned types when doing bit manipulation, passing a negative int to %X is, strictly speaking, undefined behavior.

To get rid of the higher bits, you can do

sprintf(&str_2[i * 2], "%02X", ~OWReadByte() & 0xffu);
mafso
  • 5,433
  • 2
  • 19
  • 40
  • It returns a int. Hex value that is 8 bits. – s3v3ns Jan 21 '15 at 11:24
  • 1
    8-bit types get promoted to `int` (and a value is a value, "hex" is a way to _represent_ certain values). – mafso Jan 21 '15 at 11:27
  • @s3v3ns the format specifiers cannot be used to truncate (except decimal places) - if the value does not fit the format, then the format breaks, not the value. – Weather Vane Jan 21 '15 at 11:29
  • Well the whole idea is printing the hex value onto the LCD (I know hex and binary is pretty much the same). I said it the way I said it, because in my mind it made things a bit clearer. – s3v3ns Jan 21 '15 at 11:29
  • Well i had never used format specifiers before and i just used them blindly out of frustrating in hopes they will work, i will edit the code so people can leave that part alone – s3v3ns Jan 21 '15 at 11:35
  • It is important to correct the value, because i will be using OWReadByte a lot. But as i said, i am pretty sure the FF doesn't come from the function it self, because of the LEDs it is working just fine. Of course that might be because it does not show the higher 8 bits on the LEDs. – s3v3ns Jan 21 '15 at 11:40
  • @s3v3ns, I hadn't seen the edit of your comment... If it returns an `int`, then the same applies without integer promotions: `~0xfe` is `0xff01` (for a 16-bit `int`, and as a bit pattern, with two's complement, this is the value -255). – mafso Jan 21 '15 at 11:41
  • @WeatherVane: Thanks, precision for `d` conversion gives the minimum number of digits to appear, not a maximal width; I confused it with `s` conversion. – mafso Jan 21 '15 at 11:42
  • You are right in there, that it is 0xFE. So it has something to do with my functions? – s3v3ns Jan 21 '15 at 11:43
  • It's the `~` operator. It operates on the whole `int`, not only on the lower 8 bits. – mafso Jan 21 '15 at 11:44
  • Are you sure the OP is interested in an unsigned 8bit integer and not in a signed one? Also why do you use the non-standard type `uint8_t` and not just `unsigned char`? – alk Jan 21 '15 at 11:54
  • @alk, Initially, I thought, the return value would be `char` and OP is confused about integer promotions. But given that the function returns an `int` where only the lower 8 bits are used, I think OP wants positive values. – mafso Jan 21 '15 at 11:58
  • @alk, `uint8_t` is a standard type, but doesn't exist on machines with `CHAR_BIT` != 8, on which the code doesn't compile. With `unsigned char`, it would compile, but do the wrong thing. I currently wonder if the cast is a good suggestion anyway, maybe I'll remove it entirely. – mafso Jan 21 '15 at 12:00
  • Removed the cast, @alk. With the assumption that `OWReadByte` returns `unsigned char` (or `uint8_t` or whatever), the cast could be thought of as "convert back to what it was before promotion and what it is supposed to be". Given that it returns `int`, "mask off the higher bits" is the more straight-forward way, I think. (And it avoids the off-topic discussion if `%X` requires `(unsigned)(unsigned char)~OWReadByte()`.) – mafso Jan 21 '15 at 12:13
  • What about: `... "%02hhX", ~OWReadByte());` :-) And btw: `uint8_t` is POSIX not C. – alk Jan 21 '15 at 12:37
  • @alk, `%hhX` looks good (maybe with an `unsigned char` cast). Is this a real suggestion for the answer or just discussing for the sake of having a discussion? Just wondering, I don't have a problem with the latter :) `uint8_t` is C99; it is optional, though (POSIX requires it, iirc), but the standard is quite clear that an implementation should provide it wherever possible. Given that `typedef unsigned char uint8_t;` is a valid way to provide this type on any machine with `CHAR_BIT` == 8, I think this type can be assumed to exist if (and only if) a `char` has 8 bits. – mafso Jan 21 '15 at 14:12
  • You are correct, the `[u]int[N]_t` are an optional part of the C-Standard. – alk Jan 21 '15 at 15:34
1

Assuming at least C99 the most simple and straight forward to fix the observed issue is to specify the correct length modifer(s).

sprintf(..., "%hhX", ~OWReadByte());

No casting, no precision is necessary.

alk
  • 69,737
  • 10
  • 105
  • 255
  • `%hX` is for `unsigned short`, which has at least 16 bits. – mafso Jan 21 '15 at 15:34
  • Then a `short` has the same range as `int`. – mafso Jan 21 '15 at 15:36
  • Are sure this is the case for a 16bit platform? – alk Jan 21 '15 at 15:39
  • Just don't try %hhX in Microsoft's compiler -- they don't support hh! – Steve Valliere Jan 21 '15 at 15:40
  • Ok, makeing my answer less precise on the effects of `h`. – alk Jan 21 '15 at 15:40
  • @SteveValliere, `%hhX` is C99, Microsoft's C library only supports C89. (Could be pointed out, perhaps, but C99 usually is considered "the" C on SO anyway.) – mafso Jan 21 '15 at 15:45
  • @alk, on a standard conforming platform, `short` must have at least 16 bit (see n1570 5.2.4.2.1), so `h` has basically no effect on `X` conversions on a 16-bit platform. In case you're interested in language-layerism, maybe have a look [here](http://stackoverflow.com/questions/4586962/what-is-the-purpose-of-the-h-and-hh-modifiers-for-printf) for why an `unsigned char` cast might be required by a strict reading of the standard. (I don't consider this a real-world issue, so +1 for the alternative approach.) – mafso Jan 21 '15 at 15:50
  • Added the missing, but necessary note on C99. @mafso: Thanks for pointing this out. – alk Jan 21 '15 at 20:28