Duvida subrotinas MikroC

Software e Hardware para uC PIC

Moderadores: andre_luis, 51, guest2003, Renie

Duvida subrotinas MikroC

Mensagempor Alesandro F Zagui » 25 Nov 2009 21:18

Esta acontecendo uma coisa estranha no meu programa, tenho 2 subrotinas:

Exemplo:
Código: Selecionar todos
void primeira(){
    segunda();
}

void segunda(){
    primeira();
}


Se eu faço uma chamada na segunda subrotina para a primeira funcionas, mas da primeira pra segunda não. Da a seguinte mensagem:

Undeclared identifier [segunda()] in expression

Porque isso acontece?
Alesandro Freire Zagui
Alesandro F Zagui
Byte
 
Mensagens: 154
Registrado em: 12 Mai 2009 11:03
Localização: Campo Mourao, Pr

Mensagempor Jozias del Rios » 25 Nov 2009 21:27

Todo compilador C por padrão é besta demais e não sabe que mais adiante você definiu a função que ele não entendeu. Até um assembler faz a montagem em dois tempos e consegue identificar símbolos que estão definidos em um ponto posterior...

(critica besta, tudo tem um motivo no C, mas isso atrapalha as vezes...)

O que vc precisa fazer é avisar ao compilador que a função "segunda" existe, e dizer qual o formato dela (isto é, quais os argumentos que ela recebe e o que ela retorna).

Faça isto:

Código: Selecionar todos

// a linha abaixo é uma prototipagem da função,
// isto é, vc não define o seu funcionamento,
// apenas declara que ela existe e qual seus argumentos.
void segunda();

void primeira(){
    segunda();
}

void segunda(){
    primeira();
}


vê se agora o compilador engole!
Os vencedores são aqueles que sabem o que fazer se perderem.
Os perdedores são aqueles que não sabem o que fazer se ganharem.
Avatar do usuário
Jozias del Rios
Byte
 
Mensagens: 279
Registrado em: 31 Out 2009 03:36
Localização: SJCampos-SP

Mensagempor Jozias del Rios » 25 Nov 2009 21:32

Ah, mas é bom avisar que a simulação ou a execução deste código que vc colocou irá resetar o microcontrolador por stack overflow.

Espero que vc entenda o que isso significa... vide datasheet/usermanual
Os vencedores são aqueles que sabem o que fazer se perderem.
Os perdedores são aqueles que não sabem o que fazer se ganharem.
Avatar do usuário
Jozias del Rios
Byte
 
Mensagens: 279
Registrado em: 31 Out 2009 03:36
Localização: SJCampos-SP

Mensagempor Alesandro F Zagui » 25 Nov 2009 22:45

Obrigado Rios

Em relação ao estouro de pilha, eu sei o que é sim, programo ASM também. hehehe.

Eu estou criando um MENU, e pra que não aconteça o reset por stack overflow, vou usar o comando switch ao invés de uma subrotina chamar outra.

Abraço.
Alesandro Freire Zagui
Alesandro F Zagui
Byte
 
Mensagens: 154
Registrado em: 12 Mai 2009 11:03
Localização: Campo Mourao, Pr

Mensagempor msamsoniuk » 25 Nov 2009 23:22

eu testei com dois compiladores aqui, gcc e sdcc, compilaram de boa. tah no K&R em algum lugar, se ele nao conhece a funcao, ele entende que ela eh um int funcao() e tah valendo... prototipo soh eh obrigatorio em C++ :)

para vc que curte asm, o sdcc produziu algo bem compacto, curto e grosso:

Código: Selecionar todos
_primeira:
   ljmp   _segunda
_segunda:
   ljmp   _primeira
_main:
   ljmp   _primeira


nota que otimizacao interessante e demoniaca: no sdcc nao dah stack overflow! :)

enquanto o gcc deu uma embelezada atoa:

Código: Selecionar todos
_primeira:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        call    L_segunda$stub
        leave
        ret

_segunda:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        call    _primeira
        leave
        ret

_main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        call    _primeira
        leave
        ret


para 68k eu acho um pouco mais compreensivel, mas ainda dah stack overflow, como seria no x86:

Código: Selecionar todos
primeira:
        link.w %a6,#0
        jbsr segunda
        unlk %a6
        rts
segunda:
        link.w %a6,#0
        jbsr primeira
        unlk %a6
        rts
main:
        link.w %a6,#0
        jbsr primeira
        unlk %a6
        rts


fiquei meio intrigado com o sdcc ser mehor que o gcc... entao lembrei de uma otimizacao que eu sempre ativava manualmente, -fomit-frame-pointer, entao acabou ficando:

Código: Selecionar todos
primeira:
        jbsr segunda
        rts
segunda:
        jbsr primeira
        rts
main:
        jbsr primeira
        rts


nao tao bom quanto o sdcc, pq ainda explode a stack :)

Jozias del Rios escreveu:Todo compilador C por padrão é besta demais e não sabe que mais adiante você definiu a função que ele não entendeu. Até um assembler faz a montagem em dois tempos e consegue identificar símbolos que estão definidos em um ponto posterior...

(critica besta, tudo tem um motivo no C, mas isso atrapalha as vezes...)

O que vc precisa fazer é avisar ao compilador que a função "segunda" existe, e dizer qual o formato dela (isto é, quais os argumentos que ela recebe e o que ela retorna).

Faça isto:

Código: Selecionar todos

// a linha abaixo é uma prototipagem da função,
// isto é, vc não define o seu funcionamento,
// apenas declara que ela existe e qual seus argumentos.
void segunda();

void primeira(){
    segunda();
}

void segunda(){
    primeira();
}


vê se agora o compilador engole!
Avatar do usuário
msamsoniuk
Dword
 
Mensagens: 2935
Registrado em: 13 Out 2006 18:04

Mensagempor Djalma Toledo Rodrigues » 26 Nov 2009 00:58

Marcelo Samsoniuk escreveu:eu testei com dois compiladores aqui, gcc e sdcc ....
para vc que curte asm, o sdcc produziu algo bem compacto, curto e grosso:

Código: Selecionar todos
_primeira:
   ljmp   _segunda
_segunda:
   ljmp   _primeira
_main:
   ljmp   _primeira


nota que otimizacao interessante e demoniaca: no sdcc nao dah stack overflow! :)

enquanto o gcc deu uma embelezada atoa:

[code]
_primeira:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
call L_segunda$stub
leave
ret

_segunda:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
call _primeira
leave
ret

_main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
call _primeira
leave
ret
[code]


Caro Marcelo

Em AVR -- Divulgação Xmega, demonstrates ser profundo conhecedor de C
Um PHD em BitC , até me convenceu. Imaginei que poderia abrir o Datasheet e Programar em C com a mesma eficiência que em ASM.

Mas, agora diande de tamanha diferença entre Códigos gerados por esses Compiladores me parece que "a vaca foi pro brejo"

Sempre vejo os defensores do C afirmarem que o Código gerado é tão eficiente , e alguns até se excedem e afirmam ser mais eficiênte (Coisa Impossível ), que o Assembly.

Vejo agora que isso é uma falácia, afirmações gratuitas .

Volto para o ASM ?

.
Editado pela última vez por Djalma Toledo Rodrigues em 26 Nov 2009 01:32, em um total de 1 vez.
Avatar do usuário
Djalma Toledo Rodrigues
Dword
 
Mensagens: 2334
Registrado em: 03 Ago 2008 13:22

Mensagempor Jozias del Rios » 26 Nov 2009 01:10

yet another ASM versus C battle
= YAAVCB
Os vencedores são aqueles que sabem o que fazer se perderem.
Os perdedores são aqueles que não sabem o que fazer se ganharem.
Avatar do usuário
Jozias del Rios
Byte
 
Mensagens: 279
Registrado em: 31 Out 2009 03:36
Localização: SJCampos-SP

Mensagempor msamsoniuk » 26 Nov 2009 02:20

opa, muito pelo contrario! veja que sao dois compiladores diferentes em tres plataformas diferentes. no caso do sdcc, foi uma jogada de mestre inferir o loop infinito e trocar call por jmp, acho que nao tem como fazer mais otimizado que isso na mao para conectar dois segmentos de codigo distintos. no caso do gcc, a primeira coisa q eu fiz foi compilar codigo sem otimizacao para x86 e 68k, pois o compilador costuma fazer maracutaias para tornar o codigo mais rapido. por exemplo:

Código: Selecionar todos
int main()
{
  int i;
  for(i=0;i!=1000000;i++);
  return 0;
}


eh compilado com otimizacoes como:

Código: Selecionar todos
main:
        move.w #15,%a0
.L5:
        lea (120,%a0),%a0
        cmp.w #255,%a0
        jbne .L5
        move.l %a0,%d0
        rts


ou seja, ele inicializa um registro de enderecos com o valor 15 e entao usa uma instrucao magica que 99% dos programadores asm para 68k nao imaginariam usar dessa forma, mas que produz uma soma do registro de endereco com ele mesmo mais uma constante mais rapido que uma soma imediata.

a maracutaia da otimizacao eh nao suprimir totalmente o for, mas reduzir: ele viu que era meio indiferente contar ateh 255 de um em um passo ou de 120 em 120, entao na pratica eh como se vc quisesse resolver um problema, daih o compilador suprimiu os 255 passos para apenas 2 e no final retornou o valor correto.

nesse codigo otimizado usei supressao do stack frame, como no terceiro exemplo q eu tinha citado. isso otimiza o codigo, mas na pratica soh funciona se vc compilar e linkar o codigo inteiro assim, pq ele passa a nao retornar as funcoes via stack, mas via registros.

o lance do stack frame eh convencao no processador, existem instrucoes em asm especificas para isso, entao vc usaria ele mesmo codificando em asm, pq se vc for linkar outro codigo, muito provavelmente ele segue essa convencao... mas eh mais lento! se vc seguir a convencao, deve funcionar com qq outra rotina... se vc otimizar, deve dar pau. e se der pau, vc tem q mudar tudo no braco.

em C a coisa facilita: usar ou nao a convencao requer ativar ou nao parametro -fomit-frame-pointer. se vc nao quer usar, eh soh fazer o rebuid do codigo inteiro sem ele... se for em asm tem q editar o codigo inteiro. e nao eh obvio dizer q nunca vai usar, pq se linkar com algum binario comercial, muito provavelmente vai ter q usar a convencao, daih o cara q usa asm reclama q nao eh compilador q liga e desliga flag e pede as contas :)

Djalma Toledo Rodrigues escreveu:
Marcelo Samsoniuk escreveu:eu testei com dois compiladores aqui, gcc e sdcc ....
para vc que curte asm, o sdcc produziu algo bem compacto, curto e grosso:

Código: Selecionar todos
_primeira:
   ljmp   _segunda
_segunda:
   ljmp   _primeira
_main:
   ljmp   _primeira


nota que otimizacao interessante e demoniaca: no sdcc nao dah stack overflow! :)

enquanto o gcc deu uma embelezada atoa:

[code]
_primeira:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
call L_segunda$stub
leave
ret

_segunda:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
call _primeira
leave
ret

_main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
call _primeira
leave
ret
[code]


Caro Marcelo

Em AVR -- Divulgação Xmega, demonstrates ser profundo conhecedor de C
Um PHD em BitC , até me convenceu. Imaginei que poderia abrir o Datasheet e Programar em C com a mesma eficiência que em ASM.

Mas, agora diande de tamanha diferença entre Códigos gerados por esses Compiladores me parece que "a vaca foi pro brejo"

Sempre vejo os defensores do C afirmarem que o Código gerado é tão eficiente , e alguns até se excedem e afirmam ser mais eficiênte (Coisa Impossível ), que o Assembly.

Vejo agora que isso é uma falácia, afirmações gratuitas .

Volto para o ASM ?

.
Avatar do usuário
msamsoniuk
Dword
 
Mensagens: 2935
Registrado em: 13 Out 2006 18:04

Mensagempor Djalma Toledo Rodrigues » 26 Nov 2009 06:58

Veja bem:

Call primeiro
...
Call segundo
...
Return
Return

Zerou o Stack pointer , foram apenas dois níveis

Código: Selecionar todos
void segunda(){
    primeira();
}

do Alesandro não esta encadeado com o anterior logo, não há com que se preoculpar.


Um compilador que muda completamente a concepção do programa transformando chamadas de Subrotinas em JUMPs , e pior sem avisar, ele pode ter boa intenção mas, é "abuso de confiança"
Se essas Subrotinas forem chamadas diversas vezes como fica ?
Afinal não faz sentido criar Subrotinas que roda apenas uma vez.

Ou faz ?

---------------------------------------------
Tá danado! rs

ASM aqui me tens de regresso
E suplicante te peço
A minha nova inscrição
Voltei pra rever minhas antigas Instruções ...
(Baseado (epa!) em Adelino Moreira)
Editado pela última vez por Djalma Toledo Rodrigues em 26 Nov 2009 09:51, em um total de 1 vez.
Avatar do usuário
Djalma Toledo Rodrigues
Dword
 
Mensagens: 2334
Registrado em: 03 Ago 2008 13:22

Mensagempor msamsoniuk » 26 Nov 2009 09:41

compilador nao muda o codigo, ele escreve um equivalente mais veloz... olha direito o codigo:

Código: Selecionar todos
void primeira(){
    segunda();
}

void segunda(){
    primeira();
}


funcao primeira: chama segunda
funcao segunda: chama primeira
funcao primeira: chama segunda
funcao segunda: chama primeira
...

e assim ao infinito. nao existe return NUNCA e o stack vai pro pau. entao o compilador nao apenas inferiu o resultado correto, como evitou um stack overflow! :)

a duvida eh algo positivo: se um grande programador asm como vc ficou na duvida se eh ou nao eh assim (acredite, eh assim!), isso prova positivamente como o compilador pode ir a fundo quando analisa codigo :)

Djalma Toledo Rodrigues escreveu:Veja bem:

Call primeiro
...
Call segundo
...
Return
Return

Zerou o Stack pointer , foram apenas dois níveis

Código: Selecionar todos
void segunda(){
    primeira();
}

do Alesandro não esta encadeado com o anterior logo, não há com que se preoculpar.


Um compilador que muda completamente a concepção do programa transformando chamadas de Subrotinas em JUMPs , e pior sem avisar, ele pode ter boa intenção mas, é "abuso de confiança"
Se essas Subrotinas forem chadas diversas vezes como fica ?
Afinal não faz sentido criar Subrotinas que roda apenas uma vez.

Ou faz ?

---------------------------------------------
Tá danado! rs

ASM aqui me tens de regresso
E suplicante te peço
A minha nova inscrição
Voltei pra rever minhas antigas Instruções ...
(Baseado (epa!) em Adelino Moreira)
Avatar do usuário
msamsoniuk
Dword
 
Mensagens: 2935
Registrado em: 13 Out 2006 18:04

Re: Duvida subrotinas MikroC

Mensagempor Djalma Toledo Rodrigues » 26 Nov 2009 10:14

Alesandro F Zagui escreveu:Esta acontecendo uma coisa estranha no meu programa, tenho 2 subrotinas:

Exemplo:
Código: Selecionar todos
void primeira(){
    segunda();
}

void segunda(){
    primeira();
}


Se eu faço uma chamada na segunda subrotina para a primeira funcionas, mas da primeira pra segunda não. Da a seguinte mensagem:

Undeclared identifier [segunda()] in expression

Porque isso acontece?


Veja bem o Alesandro fala em Duas Subrotinas certamente, subentende-se,
que havia Return caso contrário não seriam duas.

Vamos aguardar ele esclarecer.
.
Editado pela última vez por Djalma Toledo Rodrigues em 26 Nov 2009 10:22, em um total de 3 vezes.
Avatar do usuário
Djalma Toledo Rodrigues
Dword
 
Mensagens: 2334
Registrado em: 03 Ago 2008 13:22

Re: Duvida subrotinas MikroC

Mensagempor msamsoniuk » 26 Nov 2009 10:19

para este codigo que esta aih eh exatamente como eu falei: nao retorna nunca. agora, para outro codigo eh de outro jeito... mas como eu vou PREVER outro codigo sem ele nunca ter sido postado? daih nao tem como neh.

Djalma Toledo Rodrigues escreveu:
Alesandro F Zagui escreveu:Esta acontecendo uma coisa estranha no meu programa, tenho 2 subrotinas:

Exemplo:
Código: Selecionar todos
void primeira(){
    segunda();
}

void segunda(){
    primeira();
}


Se eu faço uma chamada na segunda subrotina para a primeira funcionas, mas da primeira pra segunda não. Da a seguinte mensagem:

Undeclared identifier [segunda()] in expression

Porque isso acontece?


Veja bem o Alesandro fala em Duas Subrotinas
certamente subentende-se que colocou Return caso contrário não seriam duas.

Vamos aguardar ele esclarecer.
.
Avatar do usuário
msamsoniuk
Dword
 
Mensagens: 2935
Registrado em: 13 Out 2006 18:04

Mensagempor Jozias del Rios » 26 Nov 2009 14:30

veja o codigo, DJ

Código: Selecionar todos
primeira:
  call segunda
  return

segunda:
   call primeira
   return


o compilador que trocou "call" por "jump" na verdade fez pouca coisa, nada demoniaca, pois ele usou o call forwarding, que eu uso direto em meus codigos em assembly para economizar instruções quando fica apertado e o cliente nao tem outra opção....

é como tipo:

Código: Selecionar todos
print_time:
   mov al, seconds
   call print_value
   mov al, minutes
   call print_value
   mov al, hours
   jmp print_value
  ; ao inves de um 'call' seguido de 'return'!


reflita bem, o compilador nao foi grosseiro em trocar "calls/returns" por "jumps"
Os vencedores são aqueles que sabem o que fazer se perderem.
Os perdedores são aqueles que não sabem o que fazer se ganharem.
Avatar do usuário
Jozias del Rios
Byte
 
Mensagens: 279
Registrado em: 31 Out 2009 03:36
Localização: SJCampos-SP

Mensagempor Alesandro F Zagui » 26 Nov 2009 14:51

Sou iniciante em C, e acabei ficando um pouco perdido no decorrer desse tópico. Vou ler com mais calma depois pra entender melhor.

Na verdade minha dúvida já foi esclarecida!!!! Obrigado a todos pela ajuda.

Abraço.
Alesandro Freire Zagui
Alesandro F Zagui
Byte
 
Mensagens: 154
Registrado em: 12 Mai 2009 11:03
Localização: Campo Mourao, Pr

Mensagempor Jozias del Rios » 26 Nov 2009 15:03

Poisé Alesandro, a galera embala fácil fácil, mas como tu disse que sabe algum assembly, não vai encontrar dificuldades intransponíveis para imaginar os mecanismos na mistureba de instruction-sets dos posts do Marcelo :-P
Os vencedores são aqueles que sabem o que fazer se perderem.
Os perdedores são aqueles que não sabem o que fazer se ganharem.
Avatar do usuário
Jozias del Rios
Byte
 
Mensagens: 279
Registrado em: 31 Out 2009 03:36
Localização: SJCampos-SP

Próximo

Voltar para PIC

Quem está online

Usuários navegando neste fórum: Nenhum usuário registrado e 1 visitante

x