Inicializar int afeta o valor de retorno da função

Desculpe pela imprecisão do título desta pergunta, mas não sei como perguntar exatamente.

O código a seguir, quando executado em um microprocessador Arduino (c ++ compilado para um microprocessador ATMega328), funciona bem. Os valores retornados são mostrados nos comentários no código:

// Return the index of the first semicolon in a string
int detectSemicolon(const char* str) {

    int i = 0;

    Serial.print("i = ");
    Serial.println(i); // prints "i = 0"

    while (i <= strlen(str)) {
        if (str[i] == ';') {
            Serial.print("Found at i = ");
            Serial.println(i); // prints "Found at i = 2"
            return i;
        }
        i++;
    }

    Serial.println("Error"); // Does not execute
    return -999;
}

void main() {
    Serial.begin(250000);
    Serial.println(detectSemicolon("TE;ST")); // Prints "2"
}

Isso gera "2" como a posição do primeiro ponto e vírgula, conforme o esperado.

No entanto, se eu alterar a primeira linha dodetectSemicolon função paraint i; ou seja, sem a inicialização explícita, eu tenho problemas. Especificamente, a saída é "i = 0" (boa), "Encontrada em i = 2" (boa), "-999" (ruim!).

Portanto, a função está retornando -999, apesar de ter executado a instrução print imediatamente antes de umreturn 2; linha e apesar de nunca executar a declaração de impressão imediatamente antes doreturn -999; linha.

Alguém pode me ajudar a entender o que está acontecendo aqui? Eu entendo que variáveis dentro de funções em c podem teoricamente conter qualquer lixo antigo, a menos que sejam inicializadas, mas aqui estou verificando especificamente uma declaração de impressão de que isso não aconteceu e ainda ...

EDIT: Obrigado a todos que participaram, e principalmente ao underscore_d por sua ótima resposta. Parece que um comportamento indefinido está realmente fazendo com que o compilador pule qualquer coisa que envolvai. Aqui estão algumas das montagens com o serial.prints dentro do detectSemicolon comentado:

void setup() {
    Serial.begin(250000);
    Serial.println(detectSemicolon("TE;ST")); // Prints "2"
  d0:   4a e0           ldi r20, 0x0A   ; 10
  d2:   50 e0           ldi r21, 0x00   ; 0
  d4:   69 e1           ldi r22, 0x19   ; 25
  d6:   7c ef           ldi r23, 0xFC   ; 252
  d8:   82 e2           ldi r24, 0x22   ; 34
  da:   91 e0           ldi r25, 0x01   ; 1
  dc:   0c 94 3d 03     jmp 0x67a   ; 0x67a <_ZN5Print7printlnEii>

Parece que o compilador está desconsiderando completamente o loop while e concluindo que a saída sempre será "-999" e, portanto, nem se preocupa com uma chamada para a função, em vez de codificar 0xFC19. Vou dar uma outra olhada com o serial.prints ativado, para que a função ainda seja chamada, mas acho que esse é um ponteiro forte.

EDIT 2:

Para quem realmente se importa, aqui está um link para o código desmontado exatamente como mostrado acima (no caso da UB):

https://justpaste.it/vwu8

Se você observar com cuidado, o compilador parece estar designando o registro 28 como o local dei e "inicializando" para zero na linhad8. Esse registro é tratado como se contivessei durante os loops while, instruções if, etc., e é por isso que o código parece funcionar e as instruções print são exibidas conforme o esperado (por exemplo, linha 122 onde "i" é incrementado).

No entanto, quando se trata de retornar essa pseudo-variável, esse é um passo longe demais para nosso compilador testado e testado; ele desenha a linha e nos envia para a outra instrução de retorno (a linha 120 salta para a linha 132, carregando "-999" nos registros 24 e 25 antes de retornar aomain())

Ou, pelo menos, é o máximo que posso obter com minha compreensão limitada da montagem. A moral da história é uma coisa estranha que acontece quando o comportamento do seu código é indefinido.

questionAnswers(2)

yourAnswerToTheQuestion