_Tipo bool y aliasing estricto

4 minutos de lectura

avatar de usuario
Lundin

Estaba tratando de escribir algunas macros para el uso seguro de tipos de _Bool y luego prueba de estrés mi código. Para propósitos de pruebas diabólicas, se me ocurrió este sucio truco:

_Bool b=0;
*(unsigned char*)&b = 42;

Dado que _Bool es 1 byte en la implementación sizeof(_Bool)==1), no veo cómo este truco viola el estándar C. No debería ser una violación estricta de aliasing.

Sin embargo, cuando ejecuto este programa a través de varios compiladores, tengo problemas:

#include <stdio.h>

int main(void)
{
  _Static_assert(sizeof(_Bool)==1, "_Bool is not 1 byte");

  _Bool b=0;
  *(unsigned char*)&b = 42;
  printf("%d ", b);
  printf("%d", b!=0 );

  return 0;
}

(El código se basa en printf promoción implícita de argumento predeterminado a int)

Algunas versiones de gcc y clang dan salida 42 42otros dan 0 0. Incluso con las optimizaciones deshabilitadas. hubiera esperado 42 1.

Parecería que los compiladores asumen que _Bool Solo puede ser 1 o 0pero al mismo tiempo felizmente imprime 42 en el primer caso.

P1: ¿Por qué es esto? ¿El código anterior contiene un comportamiento indefinido?

P2: ¿Qué tan confiable es sizeof(_Bool)? C17 6.5.3.4 no menciona _Bool en absoluto.

  • como puede ser la salida 42 42? El segundo printf solo puede imprimir 1 o 0.

    – StoryTeller – Unslander Mónica

    4 sep 2018 a las 10:53


  • O_O lo probé. Mi mente está seriamente volada en este momento. Esto se une a mi colección de ejemplos de UB.

    – StoryTeller – Unslander Mónica

    4 sep 2018 a las 10:58

  • No sé. Aunque inicialmente me sorprendió el segundo 42, tiene sentido en retrospectiva. Porque b != 0 para _Bool se puede optimizar para simplemente b. Aunque todavía me estoy rascando la cabeza.

    – StoryTeller – Unslander Mónica

    4 sep 2018 a las 11:02


  • @RbMm Los tipos de caracteres son una excepción en las estrictas reglas de alias. Optimizer no puede causar UB basado en eso aquí.

    – usuario694733

    4 sep 2018 a las 11:04


  • En un ejemplo similar, el _Bool La optimización se combina con optimizaciones para transformar ramas en operaciones aritméticas, produciendo resultados de aspecto extraño para un código muy natural. La optimización de if (b) x++; en x+=(the representation of )b; confirma que Clang trata _Bool representaciones que no sean 0 y 1 como valores trampa que activan UB. gcc.godbolt.org/z/wPq4zq

    – Pascal Cuoq

    04/09/2018 a las 11:25


P1: ¿Por qué es esto? ¿El código anterior contiene un comportamiento indefinido?

Sí, lo hace. La tienda es válida, pero posteriormente leyendo eso como un _Bool no es.

6.2.6 Representaciones de tipos

6.2.6.1 Generalidades

5 Ciertas representaciones de objetos no necesitan representar un valor del tipo de objeto. Si el valor almacenado de un objeto tiene una representación de este tipo y lo lee una expresión lvalue que no tiene tipo de carácter, el comportamiento no está definido. […]

P2: ¿Qué tan confiable es sizeof(_Bool)? C17 6.5.3.4 no menciona _Bool en absoluto.

Le dirá de manera confiable la cantidad de bytes que se necesitan para almacenar uno _Bool. 6.5.3.4 tampoco menciona intpero no estás preguntando si sizeof(int) es confiable, y usted?

  • Asi que _Bool a; *(unsigned char*)&a = 42; printf("%d", *(unsigned char*)&a); ¿es válida?

    – KamilCuk

    4 sep 2018 a las 11:05

  • @KamilCuk Hasta donde yo sé, sí, eso es perfectamente válido.

    usuario743382

    4 sep 2018 a las 11:07

  • @ user694733: no es necesario que sea una representación trampa para tener UB. La cita anterior no requiere en absoluto el acceso a la trampa. Simplemente dando 42 para un _Bool es suficiente UB.

    – StoryTeller – Unslander Mónica

    4 sep 2018 a las 11:10


  • @Lundin no_trap_t no_trap = {b}; aún no es válido porque lee una representación de trampa. Lo que p6 significa es que si eso fuera válido (o si obtiene una representación de trampa en un miembro de la estructura de alguna otra manera), entonces realizar no_trap = no_trap; también es válido: aunque copia un miembro que tiene una representación trap, la estructura en su conjunto no la tiene.

    usuario743382

    4 sep 2018 a las 11:32


  • @Lundin: el propósito de garantizar que una estructura o unión nunca sea una representación de trampa es esencialmente decir que un compilador solo puede reemplazar la asignación de estructura con la asignación miembro por miembro si no hay patrones de bits posibles que la estructura podría contener que causaría dichas operaciones tengan efectos secundarios. Si un miembro de la estructura contiene un patrón de bits que es una representación de trampa o comparte su significado con cualquier otro, creo que el estándar permite que el miembro correspondiente de la estructura de destino contenga cualquier patrón de bits equivalente (o cualquier patrón si la fuente es una trampa). reps).

    – Super gato

    4 sep 2018 a las 16:48


¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad