2

I have the following fragment of C code for an AT89S52 microcontroller:

unsigned char x = 0x10;
unsigned char str[21];

sprintf(str, "%u", (x >> 4) );

sprintf function prototype in stdio.h:

extern int sprintf  (char *, const char *, ...);

Can someone tell me why does my string contain "256" instead of "1" ?, the x variable isn't even big enough to hold the 256 value.

I'm compiling with KEIL uVision 5, using the standard stdio.h library.

If I use:

void UlToStr(char *s, unsigned long bin, unsigned char n)
{
    s += n;
    *s = '\0';

    while (n--)
    {
        *--s = (bin % 10) + '0';
        bin /= 10;
    }
}

instead of sprintf the string holds a '1'.

Im verifying the content of the string printing it through a char-LCD 40x4 (KS 0066 compatible controller)

str_lecd1(str);

with the following functions:

void str_lcd1(unsigned char *a)
{
    int i;
    for(i=0;a[i]!='\0';i++)
     data_lcd1(a[i]);
    delay(10);
}

void data_lcd1(unsigned char x)
{
    P1 = x;
    rs = 1;
    en1 = 1;                
    delay(4);
    en1=0;
    delay(4);
}
MLuna
  • 35
  • 7
  • 3
    I find it hard to believe that this code is behaving as described. – Eugene Sh. Sep 21 '18 at 21:21
  • Are you sure that shift is what you show us? Or the initial value of `x`? – Some programmer dude Sep 21 '18 at 21:24
  • How do you know what the string is containing? – Eugene Sh. Sep 21 '18 at 21:24
  • Also, when passing values of smaller types (like `char` or `short`) to a vararg function (like `printf`) those values will be [*promoted*](http://en.cppreference.com/w/c/language/conversion#Integer_promotions) to `int` or possible `unsigned int`. – Some programmer dude Sep 21 '18 at 21:25
  • 1
    @Someprogrammerdude The result of `>>` is already `int`. – Eugene Sh. Sep 21 '18 at 21:25
  • @Someprogrammerdude the function prototype follows "extern int sprintf (char *, const char *, ...); " I'm pretty sure. Also proved the same code isolated and even compiled for Windows with printf and it worked. – MLuna Sep 21 '18 at 21:30
  • Does those three lines produce a string containing the integer `16`? I serisously doubt that. [`1` I would believe](https://ideone.com/KEpfxD). – Some programmer dude Sep 21 '18 at 21:31
  • @EugeneSh. Im printing the string's content through and LCD char by char. – MLuna Sep 21 '18 at 21:32
  • Then show us the full (but minimal) reproducing code (like in [mcve]) – Eugene Sh. Sep 21 '18 at 21:32
  • 1
    Then it's more likely a problem with your LCD functions. Either that or a bug in the compiler (which can happen but very *very* unlikely). – Some programmer dude Sep 21 '18 at 21:33
  • @EugeneSh. Yeah should show 1, my bad. – MLuna Sep 21 '18 at 21:34
  • @Someprogrammerdude, I dont think so, I used another function to build the string. void UlToStr(char *s, unsigned long bin, unsigned char n) { s += n; *s = '\0'; while (n--) { *--s = (bin % 10) + '0'; bin /= 10; } } and it worked without a problem. – MLuna Sep 21 '18 at 21:35
  • Without [mcve] this question will get closed as non-reproducible, as in any compliant C implementation this code will produce string `"1"`. – Eugene Sh. Sep 21 '18 at 21:48
  • @EugeneSh. that's the fragment of the code that gives me trouble with sprinft. I proved it with another function I added below and also compiled it for Windows with printf and worked correctly. – MLuna Sep 21 '18 at 22:32
  • 5
    Could this be an endian issue? `"%u"` indicates you are copying to an `unsigned int`. Seeing as you are using an 8-bit microcontroller, it is likely two bytes. If you print those two bytes to the LCD in the wrong order, then 0x0001 could easily be read as 0x0100, or 256. – Christian Gibbons Sep 21 '18 at 22:34
  • What result do you get for x=0x01 and you simply print x? Repeat for 0x02. Repeat for 0x02 printing x>>1 – DisappointedByUnaccountableMod Sep 21 '18 at 22:41
  • @christian gibbons How can this ever happen if the string is in decimal? – Eugene Sh. Sep 21 '18 at 23:08
  • @MLuna No it is not. If you want to get help, please provide the information people are asking you to provide. – Eugene Sh. Sep 22 '18 at 00:12
  • @EugeneSh. Hmm, yes, it seems I had gotten myself mixed up. – Christian Gibbons Sep 22 '18 at 01:53
  • @EugeneSh. edited so you can see the functions I use to send ascii to the LCD. – MLuna Sep 27 '18 at 17:14
  • also note that strictly speaking `sprintf(srt, "%u", (x >> 4) );` invokes undefined behavior, since `%u` expects an `unsigned` and not an int (which is the type of `x >> 4`). However did you try attaching a debugger to check or send the characters via UART to the PC? – phuclv Sep 27 '18 at 17:57
  • @phuclv why do you say x>>4 is an int type if x is a unsigned char type?. I also tried with %d and got the same results. Don't have any debugger at hands right now but I'll try and post my results. – MLuna Sep 27 '18 at 19:55
  • @MLuna because `unsigned char` fits in an `int`, unless `sizeof(unsigned char) == sizeof(int)` which is not true on 8051 [Is unsigned char always promoted to int?](https://stackoverflow.com/q/17882326/995714), ['Char' is promoted to 'int' when passed through in C](https://stackoverflow.com/q/23983471/995714) – phuclv Sep 28 '18 at 02:19
  • @phuclv I'm confused. Then why would it be promoted if in the function prototype it states that the function expects a char type parameter? (I just added it to the post) – MLuna Sep 28 '18 at 14:03
  • [Implicit type promotion rules](https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules) – Lundin Sep 28 '18 at 14:08
  • `extern int sprintf (char *, const char *, ...);` means the first two parameters must have those types, the remaining will be passed using [default promotion](https://stackoverflow.com/q/1255775/995714). You don't pass the integer in the first two arguments, do you? Beside that any types narrower than int will be promoted to int – phuclv Sep 28 '18 at 16:16
  • @phuclv I see... well, I've been trying to look for the source of the problem. When I run `#include unsigned char x = 0x10; unsigned char str[20]; void main(void) { sprintf(str, "%u", (x>>4)); printf("%s", str); }` for X86 it works properly... I have no idea of what could be happening here... Thank you for your support. – MLuna Sep 28 '18 at 17:02
  • @ChristianGibbons you were right! even though the function prototype states that it takes char type as arguments whenever I use int types or cast the char variable to int it works fine. Also verified that the numbers I was getting were indeed in the wrong order. – MLuna Nov 01 '18 at 22:28
  • The code in your question does not compile. You define your array as `str` and refer to it as `srt`. We can't tell what other errors you might have introduced while typing the code into your question -- which is why you should always copy-and-paste the *exact* code that you're compiling. If I replace `(x >> 4)` by `(x << 4)`, I get `"256"` in `str` (because the integer promotions convert `x` from `unsigned char` to `int`). Please read this: [mcve] – Keith Thompson Nov 01 '18 at 23:38
  • @KeithThompson thanks for the correction regarding str and srt. I already fixed that. I also mentioned that I used Keil uVision v5 IDE with a AT89s52 microcontroller, are you also using the same IDE and microcontroller? – MLuna Nov 02 '18 at 02:39
  • @MLuna: No, I'm not using the same system. Does your actual code have `(x >> 4)` or `(x << 4)`? Is the first code fragment in your question copy-and-pasted from your actual source code? (I vaguely recall that Keil is non-conforming in some areas, possibly involving integer promotions.) – Keith Thompson Nov 02 '18 at 06:20
  • @KeithThompson yes, it is copy-pasted. – MLuna Nov 02 '18 at 14:52
  • @MLuna: Then I suspect a compiler bug. (That's rarely a good guess, but in this case I think it is.) Given `unsigned char x = 0x10;`, `(x << 4)` yields a result of type `int` with the value `1`. `%u` expects an argument of type `unsigned int`, but an `int` argument is ok as long as it's with the range of both types. The other possibility is that you're mistaken about the contents of `str` (or that my reasoning is incorrect, which is always possible). – Keith Thompson Nov 02 '18 at 15:28
  • Yes, I've run into this before, and I answered a question about what appears to be the same problem you've run into. I'll close this as a duplicate. (It's not an endianness issue.) – Keith Thompson Nov 02 '18 at 18:43
  • 1
    @KeithThompson understood, thank you for the help. Voted to delete my answer so people dont get confused. – MLuna Nov 02 '18 at 19:45

0 Answers0