Ponto de entrada - Entry point
Na programação de computadores , um ponto de entrada é um ponto em um programa onde a execução de um programa começa e onde o programa tem acesso aos argumentos da linha de comando .
Para iniciar a execução de um programa , o carregador ou sistema operacional passa o controle para seu ponto de entrada. (Durante a inicialização , o próprio sistema operacional é o programa). Isso marca a transição do tempo de carregamento (e tempo de link dinâmico , se houver) para o tempo de execução .
Para alguns sistemas operacionais e linguagens de programação , o ponto de entrada está em uma biblioteca de tempo de execução , um conjunto de funções de suporte para a linguagem. O código da biblioteca inicializa o programa e então passa o controle para o programa apropriado. Em outros casos, o programa pode inicializar a própria biblioteca de tempo de execução.
Em sistemas simples, a execução começa na primeira instrução, o que é comum em linguagens interpretadas , formatos executáveis simples e carregadores de boot . Em outros casos, o ponto de entrada está em algum outro endereço de memória conhecido que pode ser um endereço absoluto ou endereço relativo ( deslocamento ).
Como alternativa, a execução de um programa pode começar em um ponto nomeado, com um nome convencional definido pela linguagem de programação ou sistema operacional ou em um nome especificado pelo chamador. Em muitas linguagens da família C , essa é uma função chamada main
; como resultado, o ponto de entrada costuma ser conhecido como a função principal .
Em linguagens JVM , como Java, o ponto de entrada é um método estático denominado main
; em linguagens CLI , como C #, o ponto de entrada é um método estático denominado Main
.
Uso
Os pontos de entrada se aplicam ao código-fonte e aos arquivos executáveis . No entanto, no desenvolvimento de software do dia-a-dia , os programadores especificam os pontos de entrada apenas no código-fonte, o que os torna muito mais conhecidos. Os pontos de entrada nos arquivos executáveis dependem da interface binária do aplicativo (ABI) do sistema operacional real e são gerados pelo compilador ou vinculador (se não corrigidos pela ABI). Outros arquivos de objeto vinculados também podem ter pontos de entrada, que são usados posteriormente pelo vinculador ao gerar pontos de entrada de um arquivo executável.
Os pontos de entrada são capazes de transmitir argumentos de comando, variáveis ou outras informações como uma variável local usada pelo Main()
método. Desta forma, opções específicas podem ser definidas na execução do programa e então interpretadas pelo programa. Muitos programas usam isso como uma forma alternativa de definir configurações diferentes ou executar uma variedade de ações usando um único programa.
Contemporâneo
Na maioria das linguagens de programação e sistemas operacionais populares de hoje, um programa de computador geralmente tem apenas um único ponto de entrada .
Em programas C , C ++ , D , Zig , Rust e Kotlin , esta é uma função chamada main
; em Java , é um método estático denominado main
(embora a classe deva ser especificada no momento da invocação) e em C # é um método estático denominado Main
.
Em muitos dos principais sistemas operacionais, o formato executável padrão tem um único ponto de entrada. No Executable and Linkable Format (ELF), usado em Unix e sistemas semelhantes ao Unix, como Linux , o ponto de entrada é especificado no e_entry
campo do cabeçalho ELF. Na GNU Compiler Collection (gcc), o ponto de entrada usado pelo vinculador é o _start
símbolo. Da mesma forma, no formato Portable Executable , usado no Microsoft Windows , o ponto de entrada é especificado pelo AddressOfEntryPoint
campo, que é herdado de COFF . Em arquivos COM , o ponto de entrada está no deslocamento fixo de 0100h.
Uma exceção ao paradigma de ponto de entrada único é o Android . Os aplicativos Android não possuem um único ponto de entrada - não há nenhuma main
função especial . Em vez disso, eles têm componentes essenciais (atividades e serviços) que o sistema pode carregar e executar conforme necessário.
Uma técnica usada ocasionalmente é o binário fat , que consiste em vários executáveis para diferentes destinos empacotados em um único arquivo. Mais comumente, isso é implementado por um único ponto de entrada geral, que é compatível com todos os destinos e ramificações para o ponto de entrada específico do destino. Técnicas alternativas incluem o armazenamento de executáveis separados em garfos separados , cada um com seu próprio ponto de entrada, que é então selecionado pelo sistema operacional.
Histórico
Historicamente, e em alguns sistemas legados contemporâneos , como VMS e OS / 400 , os programas de computador têm uma infinidade de pontos de entrada , cada um correspondendo às diferentes funcionalidades do programa. A maneira usual de denotar pontos de entrada, como usados em todo o sistema em VMS e em programas PL / I e MACRO , é anexá-los ao final do nome da imagem executável , delimitado por um cifrão ($), por exemplo directory.exe$make
.
O computador Apple I também usou isso até certo ponto. Por exemplo, um ponto de entrada alternativo no BASIC do Apple I manteria o programa BASIC útil quando o botão de reinicialização fosse pressionado acidentalmente.
Ponto de saída
Em geral, os programas podem ser encerrados a qualquer momento, retornando ao sistema operacional ou travando . Os programas em linguagens interpretadas retornam o controle ao interpretador, mas os programas em linguagens compiladas devem retornar ao sistema operacional, caso contrário, o processador simplesmente continuará executando além do final do programa, resultando em um comportamento indefinido .
Normalmente, não há um único ponto de saída especificado em um programa. No entanto, em outros casos, os tempos de execução garantem que os programas sempre terminem de maneira estruturada por meio de um único ponto de saída, o que é garantido, a menos que o próprio tempo de execução trave; isso permite que o código de limpeza seja executado, como atexit
manipuladores. Isso pode ser feito exigindo que os programas sejam encerrados retornando da função principal, chamando uma função de saída específica ou pelo tempo de execução que captura exceções ou sinais do sistema operacional.
Linguagens de programação
Em muitas linguagens de programação, a main
função é onde um programa inicia sua execução. Ele permite a organização de alto nível da funcionalidade do programa e, normalmente, tem acesso aos argumentos de comando fornecidos ao programa quando ele foi executado.
A função principal é geralmente a primeira função escrita pelo programador que é executada quando um programa é iniciado e é chamada diretamente da inicialização específica do sistema contida no ambiente de tempo de execução ( crt0 ou equivalente). No entanto, algumas linguagens podem executar funções escritas pelo usuário antes das execuções principais, como os construtores de objetos globais C ++ .
Em outras linguagens, principalmente em muitas linguagens interpretadas , a execução começa na primeira instrução do programa.
Uma lista não exaustiva de linguagens de programação segue, descrevendo sua maneira de definir o ponto de entrada principal:
APL
Em APL , quando um espaço de trabalho é carregado, o conteúdo da variável "quad LX" (expressão latente) é interpretado como uma expressão APL e executado.
C e C ++
Em C e C ++ , o protótipo de função da função principal se parece com um dos seguintes:
int main(void);
int main();
int main(int argc, char **argv);
int main(int argc, char *argv[]);
int main(int argc, char **argv, char **env);
// more specifically in C
// NOT according to the ISO C standard 5.1.2.2.1
// BUT in embedded programming depending on the µC, this form is also used
void main (void);
A função principal parece um ponto de entrada para programadores de aplicativos (o ponto de entrada do aplicativo ou o ponto de entrada principal). A programação do sistema revela mais informações sobre o programa e especifica o ponto de entrada em outro lugar (no procedimento de inicialização ou no vetor de interrupção de reinicialização para programas independentes).
Os parâmetros argc
, contagem de argumento , e argv
, vector argumento , respectivamente dar o número e os valores do programa argumentos de linha de comando . Os nomes de argc
e argv
podem ser qualquer identificador válido em C, mas é uma convenção comum usar esses nomes. Em C ++, os nomes devem ser interpretados literalmente e o "vazio" na lista de parâmetros deve ser omitido, se a conformidade estrita for desejada. Outros formatos dependentes de plataforma também são permitidos pelos padrões C e C ++, exceto que em C ++ o tipo de retorno deve ser sempre int
; por exemplo, Unix (embora não POSIX.1 ) e Windows têm um terceiro argumento que fornece o ambiente do programa , de outra forma acessível através getenv
de stdlib.h
:
int main(int argc, char **argv, char **envp);
Os sistemas operacionais baseados em Darwin , como o macOS , têm um quarto parâmetro contendo informações arbitrárias fornecidas pelo sistema operacional, como o caminho para o binário em execução:
int main(int argc, char **argv, char **envp, char **apple);
O valor retornado da função principal torna-se o status de saída do processo, embora o padrão C apenas atribua significado específico a dois valores: EXIT_SUCCESS
(tradicionalmente 0) e EXIT_FAILURE
. O significado de outros valores de retorno possíveis é definido pela implementação. Caso um valor de retorno não seja definido pelo programador, um implícito return 0;
no final da main()
função é inserido pelo compilador; esse comportamento é exigido pelo padrão C ++.
É garantido que argc
não é negativo e que argv[argc]
é um ponteiro nulo . Por convenção, os argumentos da linha de comando especificados por argc
e argv
incluem o nome do programa como o primeiro elemento se argc
for maior que 0; se um usuário digitar o comando " rm file
", o shell inicializará o rm
processo com argc = 2
e argv = {"rm", "file", NULL}
. Como argv[0]
é o nome sob o qual os processos aparecem ps
, top
etc., alguns programas, como daemons ou aqueles em execução em um interpretador ou máquina virtual (onde argv[0]
seria o nome do executável do host), podem escolher alterar seu argv para fornecer um mais descritivo argv[0]
, geralmente por meio da exec
chamada de sistema.
A main()
função é especial; normalmente, todo programa C e C ++ deve defini-lo exatamente uma vez.
Se declarado, main()
deve ser declarado como se tivesse ligação externa; não pode ser declarado static
ou inline
.
Em C ++, main()
deve estar no namespace global (ou seja ::main
), não pode ser sobrecarregado e não pode ser uma função de membro , embora o nome não seja reservado de outra forma e pode ser usado para funções de membro, classes, enumerações ou funções de não membro em outros namespaces. Em C ++ (ao contrário de C) main()
não pode ser chamado recursivamente e não pode ter seu endereço obtido.
C #
Ao executar um programa escrito em C # , o CLR procura um método estático marcado com a .entrypoint
diretiva IL, que não aceita nenhum argumento ou um único argumento do tipo string[]
e tem um tipo de retorno de void
ou int
, e o executa.
static void Main();
static void Main(string[] args);
static int Main();
static int Main(string[] args);
Os argumentos da linha de comando são transmitidos args
, de forma semelhante à forma como é feito em Java. Para versões de Main()
retorno de um número inteiro, semelhante a C e C ++, ele é passado de volta ao ambiente como o status de saída do processo.
Desde C # 7.1, existem mais quatro assinaturas possíveis do ponto de entrada, que permitem a execução assíncrona no Main()
Método.
static Task Main()
static Task<int> Main()
static Task Main(string[])
static Task<int> Main(string[])
Os tipos Task
e Task<int>
são os equivalentes assíncronos de void
e int
.
Limpar
Clean é uma linguagem de programação funcional baseada na reescrita de gráficos. O nó inicial é nomeado Start
e é do tipo *World -> *World
se muda o mundo ou algum tipo fixo se o programa só imprime o resultado após a redução Start
.
Start :: *World -> *World
Start world = startIO ...
Ou ainda mais simples
Start :: String
Start = "Hello, world!"
Um diz ao compilador qual opção usar para gerar o arquivo executável.
Lisp Comum
ANSI Common Lisp não define uma função principal; em vez disso, o código é lido e avaliado de cima para baixo em um arquivo de origem. No entanto, o código a seguir emulará uma função principal.
(defun hello-main ()
(format t "Hello World!~%"))
(hello-main)
D
Em D , o protótipo da função principal se parece com um dos seguintes:
void main();
void main(string[] args);
int main();
int main(string[] args);
Os argumentos da linha de comando são transmitidos args
, de forma semelhante à forma como é feito em C # ou Java. Para versões de main()
retorno de um número inteiro, semelhante a C e C ++, ele é passado de volta ao ambiente como o status de saída do processo.
FORTRAN
FORTRAN não tem uma sub-rotina ou função principal. Em vez disso, uma PROGRAM
instrução como a primeira linha pode ser usada para especificar que uma unidade de programa é um programa principal, conforme mostrado abaixo. A PROGRAM
instrução não pode ser usada para chamadas recursivas.
PROGRAM HELLO
PRINT *, "Cint!"
END PROGRAM HELLO
Algumas versões do Fortran, como aquelas no IBM System / 360 e mainframes sucessores, não suportam a instrução PROGRAM. Muitos compiladores de outros fabricantes de software permitirão que um programa fortran seja compilado sem uma instrução PROGRAM. Nestes casos, qualquer módulo que tenha qualquer instrução sem comentário em que nenhuma instrução SUBROUTINE, FUNCTION ou BLOCK DATA ocorra, é considerado o programa Principal.
MOSQUITO
Usando GNAT , o programador não precisa escrever uma função chamada main
; um arquivo de origem contendo um único subprograma pode ser compilado para um executável. O fichário, entretanto, criará um pacote ada_main
, que conterá e exportará uma função principal estilo C.
Vai
Na linguagem de programação Go , a execução do programa começa com a main
função dopackage main
package main
import "fmt"
func main() {
fmt.Println("Hello, World!")
}
Não há como acessar argumentos ou um código de retorno fora da biblioteca padrão do Go. Eles podem ser acessados via os.Args
e os.Exit
respectivamente, os quais estão incluídos no "os"
pacote.
Haskell
Um programa Haskell deve conter um nome main
vinculado a um valor de tipo IO t
, para algum tipo t
; que geralmente é IO ()
. IO
é uma mônada , que organiza os efeitos colaterais em termos de código puramente funcional . O main
valor representa o cálculo de efeitos colaterais feito pelo programa. O resultado do cálculo representado por main
é descartado; é por isso que main
geralmente tem tipo IO ()
, que indica que o tipo do resultado do cálculo é ()
, o tipo de unidade , que não contém nenhuma informação.
main :: IO ()
main = putStrLn "Hello, World!"
Os argumentos da linha de comando não são fornecidos para main
; eles devem ser buscados usando outra ação IO, como System.Environment.getArgs
.
Java
Os programas Java começam a ser executados no método principal de uma classe, que tem um dos seguintes títulos de método :
public static void main(String[] args)
public static void main(String... args)
public static void main(String args[])
Os argumentos da linha de comando são transmitidos args
. Como em C e C ++, o nome " main()
" é especial. Os principais métodos de Java não retornam um valor diretamente, mas um pode ser passado usando o System.exit()
método.
Ao contrário de C, o nome do programa não está incluído em args
, porque é o nome da classe que contém o método principal, portanto, já é conhecido. Também ao contrário de C, o número de argumentos não precisa ser incluído, uma vez que os arrays em Java têm um campo que controla quantos elementos existem.
A função principal deve ser incluída em uma classe. Isso ocorre porque em Java tudo deve estar contido em uma classe. Por exemplo, um programa hello world em Java pode ser parecido com:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
}
Para executar este programa, deve-se chamar java HelloWorld
no diretório onde existe o arquivo de classe compilado HelloWorld.class
). Como alternativa, os arquivos JAR executáveis usam um arquivo de manifesto para especificar o ponto de entrada de uma maneira que seja independente do sistema de arquivos da perspectiva do usuário.
LOGOTIPO
No FMSLogo , os procedimentos quando carregados não são executados. Para executá-los, é necessário utilizar este código:
to procname ... ; Startup commands (such as print [Welcome]) end
make "startup [procname]
A variável startup
é usada para a lista de inicialização de ações, mas a convenção é que isso chama outro procedimento que executa as ações. Esse procedimento pode ter qualquer nome.
OCaml
OCaml não tem main
função. Os programas são avaliados de cima para baixo.
Os argumentos da linha de comando estão disponíveis em uma matriz chamada Sys.argv
e o status de saída é 0 por padrão.
Exemplo:
print_endline "Hello World"
Pascal
Em Pascal , o procedimento principal é o único bloco sem nome no programa. Como os programas Pascal definem procedimentos e funções em uma ordem ascendente mais rigorosa do que os programas C, C ++ ou Java, o procedimento principal geralmente é o último bloco do programa. Pascal não tem um significado especial para o nome " main
" ou qualquer nome semelhante.
program Hello(Output);
begin
writeln('Hello, world!');
end.
Os argumentos da linha de comando são contados ParamCount
e acessíveis como strings por ParamStr(n)
, com n entre 0 e ParamCount
.
As versões do Pascal que suportam unidades ou módulos também podem conter um bloco sem nome em cada um, que é usado para inicializar o módulo. Esses blocos são executados antes que o ponto de entrada do programa principal seja chamado.
Perl
Em Perl , não há função principal. As instruções são executadas de cima para baixo.
Os argumentos da linha de comando estão disponíveis na matriz especial @ARGV
. Ao contrário de C, @ARGV
não contém o nome do programa, que é $0
.
PHP
O PHP não tem uma função "principal". A partir da primeira linha de um script PHP, qualquer código não encapsulado por um cabeçalho de função é executado assim que é visto.
Pique
Em Pike, a sintaxe é semelhante à de C e C ++. A execução começa às main
. A argc
variável " " mantém o número de argumentos passados para o programa. A argv
variável " " contém o valor associado aos argumentos passados para o programa.
Exemplo:
int main(int argc, array(string) argv)
Pitão
Os programas Python são avaliados de cima para baixo, como é comum em linguagens de script: o ponto de entrada é o início do código-fonte. Como as definições devem preceder o uso, os programas são normalmente estruturados com definições na parte superior e o código a ser executado na parte inferior (sem recuo), semelhante ao código para um compilador de uma passagem , como em Pascal.
Alternativamente, um programa pode ser estruturado com uma main
função explícita contendo o código a ser executado quando um programa é executado diretamente, mas que também pode ser invocado importando o programa como um módulo e chamando a função. Isso pode ser feito pelo seguinte idioma, que depende da variável interna __name__
sendo definida __main__
quando um programa é executado, mas não quando é importado como um módulo (neste caso, é definido como o nome do módulo); existem muitas variantes desta estrutura:
import sys
def main(argv):
n = int(argv[1])
print(n + 1)
if __name__ == '__main__':
sys.exit(main(sys.argv))
Nesse idioma, a chamada para o ponto de entrada nomeado main
é explícita e a interação com o sistema operacional (recebendo os argumentos, chamando a saída do sistema) é feita explicitamente por chamadas de biblioteca, que são tratadas pelo tempo de execução do Python. Isso contrasta com C, onde isso é feito implicitamente pelo tempo de execução, com base na convenção.
QB64
A linguagem QB64 não possui função principal, o código que não está dentro de uma função ou sub-rotina é executado primeiro, de cima para baixo:
print "Hello World! a =";
a = getInteger(1.8d): print a
function getInteger(n as double)
getInteger = int(n)
end function
Os argumentos da linha de comando (se houver) podem ser lidos usando a função COMMAND $:
dim shared commandline as string
commandline = COMMAND$
'Several space-separated command line arguments can be read using COMMAND$(n)
commandline1 = COMMAND$(2)
Rubi
Em Ruby , não existe uma função principal distinta. Fora Em vez disso, o código escrito de qualquer class .. end
ou module .. end
escopo é executado no contexto de um especial " main
" objeto. Este objeto pode ser acessado usando self
:
irb(main):001:0> self
=> main
Possui as seguintes propriedades:
irb(main):002:0> self.class
=> Object
irb(main):003:0> self.class.ancestors
=> [Object, Kernel, BasicObject]
Métodos definidos fora de um escopo class
ou module
são definidos como métodos privados do main
objeto " ". Como a classe de " main
" é Object
, esses métodos se tornam métodos privados de quase todos os objetos:
irb(main):004:0> def foo
irb(main):005:1> 42
irb(main):006:1> end
=> nil
irb(main):007:0> foo
=> 42
irb(main):008:0> [].foo
NoMethodError: private method `foo' called for []:Array
from (irb):8
from /usr/bin/irb:12:in `<main>'
irb(main):009:0> false.foo
NoMethodError: private method `foo' called for false:FalseClass
from (irb):9
from /usr/bin/irb:12:in `<main>'
O número e os valores dos argumentos da linha de comando podem ser determinados usando a ARGV
matriz constante:
$ irb /dev/tty foo bar
tty(main):001:0> ARGV
ARGV
=> ["foo", "bar"]
tty(main):002:0> ARGV.size
ARGV.size
=> 2
O primeiro elemento ARGV
, ARGV[0]
contém o primeiro argumento de linha de comando, não o nome do programa executado, como em C. O nome do programa está disponível usando $0
ou $PROGRAM_NAME
.
Semelhante ao Python, pode-se usar:
if __FILE__ == $PROGRAM_NAME
# Put "main" code here
end
para executar algum código apenas se seu arquivo foi especificado na ruby
chamada.
Ferrugem
No Rust, o ponto de entrada de um programa é uma função chamada main
. Normalmente, essa função está situada em um arquivo chamado main.rs
ou lib.rs
.
// In `main.rs`
fn main() {
println!("Hello, World!");
}
Além disso, a partir do Rust 1.26.0, a função principal pode retornar um Result
:
fn main() -> Result<(), std::io::Error> {
println!("Hello, World!");
Ok(()) // Return a type `Result` of value `Ok` with the content `()`, i.e. an empty tuple.
}
Rápido
Quando executado em um Xcode Playground, o Swift se comporta como uma linguagem de script, executando instruções de cima para baixo; o código de nível superior é permitido.
// HelloWorld.playground
let hello = "hello"
let world = "world"
let helloWorld = hello + " " + world
print(helloWorld) // hello world
Cacau - e Cocoa Touch baseados em aplicações escritas em Swift normalmente são inicializados com os @NSApplicationMain
e @UIApplicationMain
atributos, respectivamente. Esses atributos são equivalentes em sua finalidade ao main.m
arquivo em projetos Objective-C : eles declaram implicitamente a main
função que chama UIApplicationMain(_:_:_:_:)
e cria uma instância de UIApplication
. O código a seguir é a maneira padrão de inicializar um aplicativo iOS baseado em Cocoa Touch e declarar seu delegado de aplicativo.
// AppDelegate.swift
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
return true
}
}
Visual básico
No Visual Basic , quando um projeto não contém formulários, o objeto de inicialização pode ser o Main()
procedimento. A Command$
função pode ser usada opcionalmente para acessar a parte do argumento da linha de comando usada para iniciar o programa:
Sub Main()
Debug.Print "Hello World!"
MsgBox "Arguments if any are: " & Command$
End Sub
Xojo
No Xojo , existem dois tipos de projeto diferentes, cada um com um ponto de entrada principal diferente. Os aplicativos de desktop (GUI) começam com o App.Open
evento do Application
objeto do projeto . Os aplicativos de console começam com o App.Run
evento do ConsoleApplication
objeto do projeto . Em ambos os casos, a função principal é gerada automaticamente e não pode ser removida do projeto.
Veja também
- crt0 , um conjunto de rotinas de inicialização de execução vinculadas a um programa C
- Sistema de tempo de execução
Referências
links externos
- Olá de um mundo livre de libc! (Parte 1) , 16 de março de 2010
- Como o método principal funciona em Java