0

may you please tell me why by running this two codes I have different output?

    void UART_OutString(unsigned char buffer[]){
    int i;
    while(buffer[i]){
        UART_OutChar(buffer[i]);
        i++;
    }
}

and

    void UART_OutString(unsigned char buffer[]){
  int i = 0;
  while(buffer[i]){
     UART_OutChar(buffer[i++]);
  }
}

regards, Genadi

Gendozz
  • 83
  • 5

3 Answers3

1

You didn't initialize the i variable in the first case, so it's an uninteresting typo bug that your compiler ought to warn you about...


That being said, we can apply the KISS principle and rewrite the whole code in the most readable way possible, a for loop, which by its nature makes it very hard to forget to initialize the loop iterator:

void UART_OutString(const char* buf[]){
  for(int i=0; buf[i]!='\0'; i++){
     UART_OutChar(buffer[i]);
  }
}

As it turns out, the most readable way is very often the fastest way possible too.

(However, int might be inefficient on certain low-end systems, so if you are fine with only using strings with length 255 or less, uint8_t i would be a better choice. Embedded systems should never use int and always the stdint.h types.)

Lundin
  • 195,001
  • 40
  • 254
  • 396
0

For what it's worth, I'd implement this as

void UART_OutChar(unsigned char c);

void UART_OutString(unsigned char buffer[]){
    for(unsigned char *p = buffer; *p; p++) {
        UART_OutChar(*p);
    }
}

to avoid the separate counter variable at all.

AKX
  • 152,115
  • 15
  • 115
  • 172
  • could you please explain why it's better not to reserve a counter? – Gendozz Dec 09 '20 at 11:17
  • @Gendozz with a counter you need to increment the counter in each iteration. And you also need to add the counter to the pointer value each time. If you remove the counter, you only need to increment the pointer value. – Gerhardh Dec 09 '20 at 11:19
  • 1
    This isn't necessarily better. UART means this is an embedded system. Lets assume an 8 bit microcontroller with 8 bit index registers but 16 bit address bus. This code will then enforce 16 bit arithmetic instead of 8 bit, resulting in much slower code. – Lundin Dec 09 '20 at 11:21
0

It is always a good idea to initialize local variables, especially in C where you should assume that nothing is done for you (because that's usually the case). There is a reason why regulated languages would not allow you to do this.

I believe reading the unassigned variable will result in unspecified behaviour (effectively C doesn't know there isn't meant to be anything there and will just grab what ever), this means it is completely un-predictable.

This could also cause all kinds of problems as you then index an array with it and C will not stop you from indexing an array out of bounds so if the random i value C happens to grab is larger than the size of the array then you will experience undefined behaviour in what buffer[i] returns. This one could be particularly nasty as it could cause any kind of memory read / segmentation fault are crash your program depending on quite what it decides to read.

Therefor unassigned i = random behaviour, and you then get more random behaviour from using that i value to index your array.

I believe this is about all the reasons that this is a bad idea. In C it is particular important to pay attention to things like this as it will often allow you to compile and run your code.

Both initialising i, and using the solution in @AKX's answer are good solutions although i thaught this would more answer your question of why they return differently. To which really the answer is the first approach returns completely randomly

Jack Walton
  • 181
  • 11
  • On most systems, reading an uninitialized local variable (which doesn't have its address taken) results in _unspecified_ behavior. Using such a variable as array index is however almost certainly _undefined_ behavior because of out-of-bounds access. – Lundin Dec 09 '20 at 11:30
  • Thanks Lundin I will edit my answer to use the correct term in each instance. Although if there is a technical difference i'd love if you could explain? – Jack Walton Dec 09 '20 at 11:36
  • 1
    Regarding the specific case of uninitialized variables, see [this](https://stackoverflow.com/a/40674888/584518). Regarding undefined behavior vs unspecified behavior, see [What is undefined behavior and how does it work?](https://software.codidact.com/q/277486). The TL;DR is: undefined behavior means that any wild and crazy thing can happen, such as the code getting optimized out. Wheras unspecified behavior is undocumented and compiler-/system specific behavior that may give unexpected results if relied upon, but won't cause the compiler to go completely bananas like undefined behavior might. – Lundin Dec 09 '20 at 12:21
  • Cheers, oh I rarely depend on my C code not going completely and utterly bananas anyway lol – Jack Walton Dec 09 '20 at 12:31