Trabalhando com código não-gerenciado
Neste artigo veremos um dos principais itens de código não-gerenciado na plataforma .Net que é o código inseguro.
Trabalhando com código não-gerenciado
Introdução
Felizmente a equipe da plataforma .Net e C# tornaram fácil a vida dos programadores que desejam interoperar com código existente pelo uso de código não-gerenciado. O código não-gerenciado da plataforma .Net e C# refere-se ao código que não é gerenciado e nem controlado em tempo de execução pela .Net.
Neste artigo veremos um dos principais itens de código não-gerenciado na plataforma .Net que é o código inseguro.
O código inseguro nos permite escrever código em C# utilizando construções, como os ponteiros, nos nossos aplicativos em C#.
Qualquer programador em C ou C++ sabe o quanto pode ser útil a utilização de ponteiros, por isso mesmo C# sendo uma linguagem muito segura nos fornece essa possibilidade de trabalhar com ponteiros, ai que entra o código inseguro no C#. Apesar do nome “código inseguro”, isso não significa que seja um código perigoso, ou então um código não confiável, na realidade trata-se apenas de um código na qual em tempo de execução a plataforma .Net não controla a alocação e a desalocação de memória. Esse é um dos grandes motivos pela utilização de ponteiros ser chamada de código inseguro, imagine m programador alocar vários megabytes de memória e esquecer de desalocar toda essa quantidade de memória usada, poderia se tornar uma catástrofe para qualquer aplicação.
A grande vantagem da utilização de código inseguro é quando queremos utilizar ponteiros para comunicação com código de legado, ou então por questão de desempenho quando seu aplicativo manipula de forma direta a memória.
Utilizando o código inseguro
Para utilizarmos código inseguro buscamos duas palavras chaves, são elas unsafe e fixed.
De forma geral a palavra-chave unsafe indica que o bloco marcado executará em um contexto na qual não é gerenciado. Utilizamos a palavra-chave em métodos, e blocos de código dentro dos próprios métodos.
A palavra-chave fixed é responsável por indicar ao garbage collector que o objeto não pode ser movido. O que acontece aqui é que a plataforma .Net move os objetos na memória para tornar a utilização dela mais eficiente. Essa é uma palavra-chave que deve ser usada com muito cuidado, visto que os objetos são movidos na memória para melhorar a eficiência podemos causar estragos, imagine que temos vários ponteiros alocados numa memória e usamos a palavra-chave em questão, o que faria com que os endereços de memórias dos ponteiros fossem movidos para outros locais de memória, tornando assim os ponteiros inválidos.
Utilizando ponteiros
Os ponteiros utilizados em C# são os mesmos que e utilizando em C e C++. Assim o “&” retorna um ponteiro que representa o endereço de memória da variável. O operador “*” utiliza-se para denotar o valor indicado pelo ponteiro. E por último o operador “->” é utilizado para acesso de membro e desreferenciamento de ponteiro.
|
Operador |
Significado |
|
& |
Retorna um ponteiro que será um endereço de memória da variável. |
|
* |
Denota o valor indicado pelo ponteiro |
|
-> |
Acessa um membro e desreferencia o ponteiro |
Exemplificando ponteiros em unsafe
Vamos fazer dar um exemplo com a utilização de ponteiros no modo unsafe. Neste exemplo observamos as variáveis antes da função Recebe() e depois dela. Exemplificando assim a utilização valiosa de ponteiros executando em código inseguro. Não se esqueça que para compilar em código inseguro devemos utilizar a opção /unsafe do compilador.
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication3
{
class Program
{
public static unsafe void Recebe(int* x, int* y)
{
*x = 11;
*y = 22;
}
static unsafe void Main(string[] args)
{
int a = 1;
int b = 2;
System.Console.WriteLine("Antes de chamar a função Recebe():
a = , b = ", a, b);
Recebe(&a, &b);
System.Console.WriteLine("Depois de chamar a função Recebe():
a = , b = ", a, b);
System.Console.ReadLine();
}
}
}
A saída do nosso exemplo acima deverá ser da seguinte maneira:
Antes de chamar a função Recebe(): a = 1, b = 2
Depois de chamar a função Recebe(): a = 11, b = 22
Utilizando o fixed
A instrução fixed usa-se com a sintaxe fixed(tipo *ponteiro = expressão) instrução. Para ficar mais simples o entendimento da instrução, vamos a um exemplo prático de como utilizar a instrução fixed.
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication3
{
class Futebol
{
public int x;
}
class Program
{
unsafe static void SetarFutebolValor(int *x)
{
Console.WriteLine("Desreferenciado o ponteiro para modificar
futebol.x");
*x = 42;
}
unsafe static void Main(string[] args)
{
Futebol futebol = new Futebol();
Console.WriteLine("futebol.x inicializa com ", futebol.x);
fixed (int* f = &futebol.x)
{
Console.WriteLine("Chamando SetarFutebolValor() passando
ponteiro para futebol.x");
SetarFutebolValor(f);
}
Console.WriteLine("Depois retorna para SetarFutebolValor(),
futebol.x = ",futebol.x);
System.Console.ReadLine();
}
}
}
Este simples código mostra como podemos utilizar a instrução fixed. A instrução fixed no código acima fica o objeto “futebol” até a instrução composta envolvente terminar. Nesta linha “fixed(int* f = &futebol.x)” podemos ver a atribuição de um endereço do objeto “futebol” a um “Futebol*”.
Devemos salientar que a instrução fixed é utilizada somente para inclusão de um código que será afetado se o Garbage Collector fosse o mover o objeto futebol. Isso é importante em casos de termos blocos de código maiores com grandes quantidades de códigos onde queremos minimizar a quantidade de tempo em que tem um objeto fixado.
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Artigo