Sat. Oct 1st, 2022

En este artículo analizaremos los operadores de puntero, la aritmética de punteros y dos situaciones en las que los punteros pueden mejorar su código.

información de soporte

Trabajar con valores de puntero

Modificación y desreferenciación de punteros

Hay dos valores asociados con un puntero. La primera es la dirección de memoria que se almacena en el propio puntero, y la segunda es la información que se almacena en esta dirección de memoria. Para modificar la dirección almacenada en la variable de puntero, simplemente use el signo igual:

                    RxByte_ptr = 0x40;
                  

Para acceder a los datos almacenados en la dirección del puntero, utilice un asterisco. Esto funciona tanto para leer como para escribir.

                    ReceivedData = * RxByte_ptr;
* TxByte_ptr = TransmitData;
                  

El acceso al valor al que se apunta un puntero se llama desreferenciación, y el asterisco (cuando se usa con punteros) se llama el operador de desreferencia.

Obtención de la dirección de una variable

Un detalle importante relacionado con el uso de punteros es el operador de "dirección de C"; El símbolo para esto es &. Aunque el & está asociado a variables normales en lugar de punteros, todavía lo considero un "operador de puntero" porque su uso está muy relacionado con la implementación del puntero.

Cuando se coloca un & delante de un nombre de variable, el programa utiliza la dirección de la variable en lugar del valor de la variable.

Esto le permite colocar la dirección de una variable en un puntero, aunque no tenga idea de dónde se ubicará una variable en la memoria. El uso del operador & se muestra en el siguiente fragmento de código, que también sirve como resumen del uso del puntero básico.

                    char DisplayChar;
char TestingVariable;
char * DisplayChar_ptr;

DisplayChar = 0x41;
DisplayChar_ptr = & DisplayChar;
TestingVariable = * DisplayChar_ptr;
* DisplayChar_ptr = 0x42;
TestingVariable = DisplayChar;
                  

Aquí hay una descripción paso a paso de lo que hace este código:

DisplayChar = 0x41;

La variable DisplayChar ahora contiene el valor correspondiente a ASCII ‘A’.

DisplayChar_ptr = & DisplayChar;

El puntero (DisplayChar_ptr) ahora contiene la dirección de la variable DisplayChar. No tenemos idea de qué es esta dirección, es decir, no sabemos el número almacenado en DisplayChar_ptr. Además, no necesitamos saberlo; Este es el negocio del compilador, no el nuestro.

TestingVariable = * DisplayChar_ptr;

TestingVariable ahora tiene el valor de la variable DisplayChar, a saber, 0x41.

* DisplayChar_ptr = 0x42;

Acabamos de usar el puntero para modificar el valor almacenado en la dirección correspondiente a la variable DisplayChar; ahora tiene 0x42, que es ASCII ‘B’.

TestingVariable = DisplayChar;

TestingVariable ahora tiene el valor 0x42.

Aritmética de puntero

La mayoría de las veces, una variable C tiene un valor que puede variar, y las variables de puntero no son una excepción. Las operaciones aritméticas comunes que se utilizan para modificar el valor de un puntero son la suma (por ejemplo, TxByte_ptr = TxByte_ptr + 4), resta (TxByte_ptr = TxByte_ptr – 4), incremento (TxByte_ptr ++) y decrement (TxByte_ptr ++) Es posible restar un puntero de otro, siempre que los dos punteros tengan el mismo tipo de datos. Sin embargo, no puede agregar un puntero a otro puntero.

La aritmética de punteros no es tan sencilla como parece. Digamos que usted tiene un puntero con el tipo de datos de largo. Estás depurando algo de código y actualmente estás realizando un solo paso a través de una rutina que incrementa repetidamente este puntero. Observa en su ventana de Vigilancia que el valor del puntero no aumenta en uno con cada incremento. ¿Que está pasando aqui?

Si no puede pensar fácilmente en la respuesta, debería pasar un poco más de tiempo reflexionando sobre la naturaleza de los punteros. El puntero en este código se usa con variables largas, es decir, variables que consumen cuatro bytes de memoria. Cuando incrementas el puntero, en realidad no quieres que el valor del puntero aumente en una ubicación de la memoria (suponemos que la memoria está organizada en bytes). Más bien, desea que aumente en cuatro ubicaciones de memoria, de modo que apunte a la siguiente variable larga. El compilador lo sabe y modifica el valor del puntero en consecuencia.

Lo mismo ocurre cuando agrega un número a un puntero o resta un número de un puntero. La dirección almacenada en el puntero no necesariamente aumentará o disminuirá ese número; más bien, aumentará o disminuirá en ese número multiplicado por el tamaño en bytes del tipo de datos del puntero.

Punteros y matrices

Los punteros y matrices están estrechamente relacionados. Cuando declara una matriz, esencialmente está creando un puntero constante que siempre contiene la dirección de inicio de la matriz, y la notación de índice que usamos para acceder a los elementos de una matriz también se puede usar con punteros.

Por ejemplo, digamos que usted tiene un puntero char llamado TxBuffer que actualmente tiene la dirección 0x30. El siguiente fragmento de código muestra dos formas equivalentes de acceder a los datos en la dirección 0x31.

                    TxByte = * (TxBuffer + 1);
TxByte = TxBuffer[1];
                  

Cuándo usar punteros

En esta sección, quiero discutir brevemente dos situaciones de codificación que pueden beneficiarse del uso de punteros y que son particularmente relevantes para aplicaciones integradas.

Puntero contra matriz

El primero se desprende naturalmente de la discusión en la sección anterior. Los punteros proporcionan un método alternativo para tratar los datos que se almacenan en forma de una matriz. El enfoque de puntero puede ser más intuitivo o conveniente en el contexto de una rutina dada.

En algunos casos, sin embargo, una implementación basada en punteros puede resultar en un código más rápido. Mi entendimiento es que esto fue más cierto en el pasado, antes de que los compiladores fueran altamente sofisticados y capaces de una optimización tan extensa. Sin embargo, en el contexto del desarrollo integrado, creo que todavía hay algunas situaciones en las que los punteros pueden proporcionar una mejora no despreciable en la velocidad de ejecución. Si realmente está tratando de lograr la cantidad mínima de ciclos de reloj necesarios para ejecutar una parte determinada del código, vale la pena intentar los punteros.

Pasando punteros a funciones

El uso extensivo de las funciones lo ayuda a escribir código organizado y modular. Esto es bueno, aunque C impone una limitación que puede ser incómoda en algunas situaciones: una función solo puede tener un valor de retorno. En otras palabras, puede modificar solo una variable, a menos que, es decir, use punteros.

Esta técnica funciona de la siguiente manera:

  1. Incluya un puntero como una de las entradas a la función.
  2. Use el operador & para pasar la dirección de una variable a la función.
  3. Dentro de la función, la dirección de la variable se convierte en el valor del puntero, y la función utiliza el operador de desreferencia para modificar el valor de la variable original.
  4. Aunque la variable original no se modifica directamentePor medio de un valor de retorno, el código que sigue a la función asume que el valor de la variable ha sido modificado.

Aquí hay un ejemplo:

                    #define STEPSIZE 3

void IncreaseCnt_and_CheckLED (char * Count)
{
    * Count = * Count + STEPSIZE;
    si (LED == VERDADERO)
        volver VERDADERO
    más
        falso retorno;
}

int main ()
{
    char RisingEdgeCount = 0;
    bit LED_State;

    ...
    ...
    LED_State = IncreaseCnt_and_CheckLED (& RisingEdgeCount);
    ...
    ...
} 
                  

Conclusión

Espero que ahora tenga una idea clara de qué son los punteros y cómo comenzar a trabajar con ellos en su firmware en lenguaje C. Si hay algún aspecto de la C incrustada que quisiera que discutiéramos en futuros artículos, no dude en informarnos en la sección de comentarios a continuación.

By Maria Montero

Me apasiona la fotografía y la tecnología que nos permite hacer todo lo que siempre soñamos. Soñadora y luchadora. Actualmente residiendo en Madrid.