Ir ao conteúdo

Posts recomendados

Postado
#include <stdio.h>


int main() {

	unsigned long long int fib[60];
	int i;


    for(i = 0; i <= 60; i++){
    	if(i == 0){
    		fib[i] = 0;
    	}
    	else if(i == 1){
    		fib[i] = 1;
    	}
    	else{
    		fib[i] = fib[i - 1] + fib[i - 2];
    	}
    }


    for(i = 0; i <= 60; i++){
        printf("Fib(%d) = %llu\n", i, fib[i]);
    }

    return 0;
}

Pessoal, boa noite. Eu fui revisar meu código, após ter rodado sem problemas, porém me surgiu uma dúvida. Declarei uma variável, "fib[60]", ou seja, um vetor com as posições de 0 a 59, tamanho 60.

Na hora de instanciar valores e imprimir, coloquei das posições 0 a 60, ou seja, tamanho 61. E rodou sem problemas, não dando problema de compilação por causa do vetor menor do que eu estava instanciando. Não teria que ter dado o famoso stack overflow? Sistema Operacional é o Ubuntu.

Postado

Na padronização da linguagem C, em inglês, usa-se o termo "undefined behavior", ou seja, comportamento imprevisível. O que ocorre ao tentar usar um elemento que esteja fora do intervalo não é determinado pelo C. Então tudo pode acontecer. Desde nada, ou retornar um zero, até dar "segmentation fault" caso você acesse um pedaço de memoria alheia, ou congelar a maquina, formatar o HD do vizinho etc. A lista de comportamentos imprevisíveis é longa (infinita, de fato 😁).

 

Nunca, sob hipótese alguma, explore um comportamento imprevisível num projeto real.

  • Curtir 1
Postado

Então, @V!OLADOR, não quero persistir no erro. Só quero entender o que tem de certo ou errado no meu código. Declarei um vetor com 60 posições, mas consegui, sem querer, instanciar 61.

Você deu uma olhada no código?

Postado
9 minutos atrás, kampa896 disse:

Você deu uma olhada no código?

 

Não, foi mal. Bom o erro evidente você já citou:

 

for(i = 0; i < 60; i++)

 

ao invés de de i <= 60. O compilador não faria checagem do intervalo em condições normais, então seria compilável.

 

Qual o compilador? GNU gcc? dependendo da versão você pode usar a opção -fbounds-checking durante a compilação e então ele iria identificar um erro.

  • Obrigado 1
Postado

Bom, calma. Você pode utilizar essa opção nesse caso em particular, como um teste, mas não deve em hipótese alguma escrever em C confiando numa opção magica do compilador pra fazer o seu trabalho. Isso porque o seu código não vai ficar portável, ou seja, ele só poderia ser compilado por um compilador especifico. Então a recomendação oficial seria escrever o programa de acordo com a gramatica do C e, nesse caso, cuidando sempre de não acessar memoria fora do intervalo.

 

11 minutos atrás, kampa896 disse:

Esse comando vai no final do comando pra compilar, né, @V!OLADOR?

 

Sim, por exemplo, supondo que o código fonte esteja num arquivo chamado main.c, seria algo como,

 

gcc -fbounds-checking main.c -o main.out

 

  • Obrigado 1
Postado

Exato, @V!OLADOR, fui executar o comando no final, o próprio terminal ensinou a fazer dessa forma. E rodou sem problemas, não voltou nenhum erro.

Eu entrei em bug. Porque veja, sou iniciante, comecei a faculdade e não tinha contato com programação. Aí aprendi que o vetor tem seu tamanho, e posição definida por 0 até tamanho - 1, mas este programa que estou fazendo pra treinar vetores está rodando normal. Olha a tela do programa em anexo. Não entendi porque roda normal até agora.

Captura de tela de 2020-10-03 21-35-43.png

adicionado 4 minutos depois

Olha executando da forma que você ensinou, @V!OLADOR.

Captura de tela de 2020-10-03 21-42-40.png

Captura de tela de 2020-10-03 21-42-48.png

Postado

Tenta o experimento de aumentar o tamanho do for até, digamos, 100 (mantenha o vetor com 60 elementos) e vejamos o que acontece. Vamos encontrar o limite pro problema ocorrer.

  • Curtir 1
Postado

Desde já agradeço sua atenção, meu amigo, @V!OLADOR.

Olha o que apareceu pelo IDE. E vou fazer pelo terminal agora, só um instante.

Captura de tela de 2020-10-03 21-51-10.png

adicionado 3 minutos depois

Apareceu a mesma mensagem que aparece pela IDE. Não entendi como o compilador não acha o erro. Pelo que entendi, ele apenas chega no limite do tamanho de cada dado, por ser long long int. Mas não chega no limite do tamanho do vetor.

Captura de tela de 2020-10-03 21-53-32.png

Captura de tela de 2020-10-03 21-53-37.png

Postado

Bom, então vemos um limite ali, ele vai quebrar em certo momento.

 

Talvez pudéssemos aumentar a perspicácia do compilador aumentando o nível de otimização que ele faria no seu código durante a compilação. Pra fazer isso você pode usar as opções -O0, -O1, -O2 ou -O3. Provavelmente, ele sabe de antemão que o código pode funcionar sem grande perigo e então simplesmente compila. Mas se aumentarmos o nível de otimização ele talvez comece a reclamar. Tenta o seguinte:

 

gcc -O3 test.c -o test.out

 

E vejamos o que acontece.

  • Curtir 1
Postado

Caramba, meu amigo. Você acertou. Apareceu a mensagem que o loop é maior que 60 iterações.

Foi só fazer este teste de otimização do compilador.

 

Quero focar minha programação em C, você tem algum livro ou material pra indicar, @V!OLADOR?

 

Captura de tela de 2020-10-03 22-15-46.png

Postado

Curioso não? ele encontrou o problema mas não classificou como erro. Apenas alertou pra inconsistência. Isso porque a padronização de C não diz o que deve ser feito nesses casos, devemos tratar apenas como um "undefined behavior".

 

Olha, em termos de livro eu sempre recomendo a bíblia que talvez nem seja mais uma referência popular hoje em dia, chama-se "The C Programming Language (ISO C)". Escrito por um dos deuses da programação, Brian Kernighan e, ninguém mais ninguém menos, que Dennis Ritchie, o criador de C. O bom da linguagem C é ser pequena, concisa, fácil de aprender, além de extremamente poderosa, e que continua praticamente igual em mais de 40 anos. Então, apesar desse livro ter sido escrito em 1978, ainda é uma ótima referência. O link do Amazon vai em anexo abaixo.

 

https://www.amazon.com/Programming-Language-2nd-Brian-Kernighan/dp/0131103628

 

PS: acho que você consegue uma copia em pdf por ai mas não podemos promover esse tipo de material aqui no fórum. Além do mais, muito mais gratificante é comprar a obra original.

  • Amei 1
Postado

@V!OLADOR concordo plenamente com você, meu amigo. Muito gratificante comprar a obra original.

Muito obrigado por toda a atenção e ensinamentos nesse horário em pleno sábado. Gostei demais da linguagem C, estou bem no início. E quero me aprofundar na linguagem, igual você. Mais uma vez, muito obrigado!

Postado

@KXSY amigo, estou bem no início, comecei a aprender do zero.

O nome dos livros seriam "C in a nutshell" e "C completo e total"? Você teria ao menos os nomes dos autores?

 

E esse comando que você ensinou, eu coloco como no terminal? A ordem dos elementos. Como eu disse, estou bem no início e desde já agradeço sua atenção também.

Postado
8 minutos atrás, KXSY disse:

Ao meu ver seria melhor usar o -fsanitize=address e deixar o programa quebrar por si só.

 

 

Eu concordo com você, @KXSY. Eu evitei o sanitize, pelo menos por hora, porque talvez fosse mais confuso pra ele. Meu objetivo era apenas colocar o compilador sob estresse pra ver como/quando o problema seria detectado.

  • Obrigado 1
Postado

Percebi. O terminal da mais acesso e controle do compilador. Agradeço a atenção, meu amigo. Vocês foram feras em me apoiar. Fiquei a tarde inteira pesquisando, e não consegui delimitar o problema até postar aqui no fórum e vocês me auxiliarem. Vou atrás desses livros. Obrigado mais um vez, @KXSY!

adicionado 12 minutos depois

E só pra dar um retorno pra vocês, este sanitize realmente foi direto no problema, o tamanho da variável que declarei o vetor. Obrigado, pessoal!

Captura de tela de 2020-10-03 23-59-23.png

Postado
1 hora atrás, KXSY disse:

É realmente isso e um porre em C não ter um sistema de checagem decente, eu sabia uma diretiva do compilador que fazia exatamente isso que o -O2 faz mas eu esqueci

 

Manter ativo um check de índices durante toda a vida e execução de um programa pode significar uma carga enorme, maior que 10 % em termos de tamanho do código gerado e mais ainda no tempo de execução. Lembra dos tempos românticos da introdução da linguagem Pascal do prof, Wirth e as mensagens "array out of bounds" em tempos de execução e os adeptos dizendo de como era "melhor que FORTRAN" que dava uns erros malucos que na época eram chamados ABEND --- IBM: ABnormal END --- a versão mainframe do depois gerado SIGSEGV, o stack overflow do Unix depois Linux.

 

Um atraso assim grande em uma linguagem que foi escrita para programação de sistemas não tem sentido. Se imagina que os desenvolvedores façam o que o autor fez: identifiquem o erro de alguma forma. Ou durante o desenvolvimento usem ferramentas como sanitizers ou analizadores estáticos que leêm os programas e buscam por fragilidades conhecidas, como erros one-off ou troca de == por = em expressões.

 

Hoje em dia os sistemas são bem sólidos, mas durante muito tempo um ponteiro perdido por exemplo podia parar o sistema operacional, nas primeiras versões de Unix antes dos chips de MMU que controlavam o acesso à memória, o stack e o overflow dele pelos processos no sistema.

 

 

  • Confuso 1
Postado
agora, kampa896 disse:

desculpa, meu amigo, mas sou iniciante demais pra entender o que você quis dizer. Isso foi uma crítica ou um elogia a linguagem C? 🤔

 

Quem sou eu para criticar uma linguagem? :)  


C é sensacional. E considerando que os sistemas operacionais e os compiladores para as outras linguagens foram e mesmo hoje são escritos em grande parte em C nem faria sentido querer criticar. Os números derrubariam qualquer tentativa.

 

O que eu disse foi que é preciso entender que nem todo caso é trivial como o que expôs, e o eventual estouro do índice pode ocorrer uma vez em um milhão de execuções. Só que C é a linguagem para escrever coisas que rodam milhões de vezes toda hora. Então você não pode pagar o preço do atraso que dá ficar testando em cada expressão *(x + i + j) se isso vai levar a uma área não alocada pelo programa. Seria muito romântico.

 

Pascal é uma linguagem que inicialmente fazia isso por padrão e por isso citei.

 

MMU era um tipo de chip que controlava o acesso a memória pelos processos via hardware e permitia uma maior tolerância dos sistemas a erros do tipo que você descreveu.

 

ABEND era o nome que a IBM dava a um erro que cancelava um programa. Tipo o erro de segmentação. E podia gerar um DUMP, que era uma listagem da memória na impressora para ajudar a achar o erro. Em tempos antigos, anos 70/80

Postado

Ah sim, @arfneto, desculpa não ter entendido o que você quis dizer, muitos termos que não fizeram sentido pra mim, mas nessa segunda explicação, ficou claro o seu comentário. Obrigado pelo apoio e tempo gasto pra analisar meu tópico e contribuir. Não é à toa que o Clube do Hardware se destaca até hoje, mesmo sendo tão antigo.

  • Curtir 1

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

GRÁTIS: ebook Redes Wi-Fi – 2ª Edição

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!