Estoy escribiendo una aplicación Bluetooth Mesh con el chip nRF51 de Nordic Semiconductor y, mientras miraba algunos ejemplos, me topé con este código:

nrf_mesh_address_t address = {NRF_MESH_ADDRESS_TYPE_INVALID, 0, NULL};
                   address.type = NRF_MESH_ADDRESS_TYPE_GROUP;
                   address.value = GROUP_ADDRESS;

A medida que leo este fragmento address se define por primera vez con algunas variables que se cambian inmediatamente de nuevo. ¿No es innecesaria esta doble definición?

La definición de nrf_mesh_addrees_t se ve así:

typedef struct
{
    nrf_mesh_address_type_t type;
    uint16_t value;
    const uint8_t* p_virtual_uuid;
} nrf_mesh_address_t;

Mi primer pensamiento fue que p_virtual_uuid se declaró const, por lo que no se pudo cambiar después de la definición, pero no recibí un error de compilación al cambiar el código a esto:

nrf_mesh_address_t address;
                   address.type = NRF_MESH_ADDRESS_TYPE_GROUP;
                   address.value = GROUP_ADDRESS;
                   address.p_virtual_uuid = NULL;

¿Hay alguna ventaja en definir la variable dos veces con diferentes variables?

1
SørenHN 23 oct. 2017 a las 13:17

3 respuestas

La mejor respuesta

Sí, eso parece muy redundante.

Si está utilizando C99, sugeriría:

nrf_mesh_address_t address = { .type = NRF_MESH_ADDRESS_TYPE_GROUP,
                               .value = GROUP_ADDRESS,
                               .p_virtual_uuid = NULL };

const se refiere a los datos que se apuntan, no al puntero en sí. El último sería uint8_t * const p_virtual_uuid.

6
unwind 23 oct. 2017 a las 10:29

Tiene razón en que son redundantes y es equivalente a su último fragmento de código.

Sin embargo, veo un valor potencial para el primer uso. Por ejemplo, si desea aplicar una política de inicialización siempre de variables. Podría tener la inicialización predeterminada

nrf_mesh_address_t address = {NRF_MESH_ADDRESS_TYPE_INVALID, 0, NULL};

Disponible y listo para ser copiado.

Esto puede evitar situaciones como esta:

nrf_mesh_address_t address;
                   address.type = NRF_MESH_ADDRESS_TYPE_GROUP;
                   address.value = GROUP_ADDRESS;

Quería establecer type y value y dejar p_virtual_uuid en el valor predeterminado . Sin embargo, olvidé inicializarlo y ahora tengo un error en mi código.

Sin embargo, el valor de esta práctica es discutible. Solo quería mostrar una posible motivación válida.

1
bolov 23 oct. 2017 a las 10:25

La miembro de datos

const uint8_t* p_virtual_uuid;

No es un miembro de datos constante. Es un puntero no constante que apunta a un objeto constante.

Una declaración de un puntero constante que apunta a un objeto constante se verá como

const uint8_t * const p_virtual_uuid;

En este caso, debe inicializar el miembro de datos cuando se define un objeto del tipo de estructura.

Las declaraciones de expresión que siguen a la declaración en este fragmento de código

nrf_mesh_address_t address = {NRF_MESH_ADDRESS_TYPE_GROUP, 0, NULL};
                   address.type = NRF_MESH_ADDRESS_TYPE_GROUP;
                   address.value = GROUP_ADDRESS;

Son redundantes

Podrías escribir

nrf_mesh_address_t address = {NRF_MESH_ADDRESS_TYPE_INVALID, GROUP_ADDRESS, NULL};

O podría usar designaciones en la lista de inicializadores. Por ejemplo

nrf_mesh_address_t address = 
{ 
    .type = NRF_MESH_ADDRESS_TYPE_INVALID, 
    .value = GROUP_ADDRESS, 
    .p_virtual_uuid = NULL
};

Frente a C ++, hay un problema con los inicializadores de lista entre paréntesis en C. Las evaluaciones de las expresiones de inicialización no están secuenciadas. Entonces, si el valor de un initioalizer depende del valor de otro inicializador, entonces necesitará usar asignaciones en lugar de inicializar expresiones en una lista encerrada entre llaves.

Del Estándar C (6.7.8 Inicialización)

23 El orden en que ocurren los efectos secundarios entre las expresiones de la lista de inicialización no está especificado.

2
Vlad from Moscow 23 oct. 2017 a las 12:03