c++ - ¿Es seguro memset bool a 0?
language-lawyer (4)
Supongamos que tengo algún código heredado que no se puede cambiar a menos que se descubra un error y este código:
bool data[32];
memset(data, 0, sizeof(data));
¿Es esta una manera segura de establecer todos los bool
en la matriz a un valor false
?
En términos más generales, ¿es seguro memset
un bool
en 0
para que su valor sea false
?
¿Está garantizado que funcione en todos los compiladores? ¿O debo solicitar una solución?
Creo que esto no se especifica, aunque parece probable que la representación subyacente de false
sea todo ceros. Boost.Container se basa en esto también ( énfasis mío ):
Boost.Container utiliza std :: memset con un valor cero para inicializar algunos tipos, ya que en la mayoría de las plataformas esta inicialización cede a la inicialización del valor deseado con un mejor rendimiento.
Siguiendo el estándar C11, Boost.Container supone que para cualquier tipo de entero, la representación del objeto donde todos los bits sean cero será una representación del valor cero en ese tipo. Como _Bool / wchar_t / char16_t / char32_t también son tipos enteros en C, considera todos los tipos integrales de C ++ como inicializables a través de std :: memset.
Esta cita de C11 a la que señalan como un razonamiento en realidad proviene de un defecto de C99: defecto 263: representaciones de bits con cero bits que agregaron lo siguiente:
Para cualquier tipo de entero, la representación del objeto donde todos los bits son cero debe ser una representación del valor cero en ese tipo.
Entonces, la pregunta aquí es la suposición correcta, ¿la representación del objeto subyacente para el entero es compatible entre C y C ++? La propuesta Resolviendo la diferencia entre C y C ++ con respecto a la representación de objetos de enteros buscó responder a esto hasta cierto punto, que hasta donde yo sé no fue resuelto. No puedo encontrar evidencia concluyente de esto en el borrador del estándar. Tenemos un par de casos donde se vincula explícitamente con el estándar C con respecto a los tipos. La sección 3.9.1
[basic.fundamental] dice:
[...] Los tipos enteros con signo y sin signo cumplirán las restricciones dadas en el estándar C, sección 5.2.4.2.1.
y 3.9
[basic.types] que dice:
La representación del objeto de un objeto de tipo T es la secuencia de N objetos de signo sin signo tomados por el objeto de tipo T, donde N es igual a sizeof (T). La representación del valor de un objeto es el conjunto de bits que contiene el valor del tipo T. Para los tipos que se pueden copiar trivialmente, la representación del valor es un conjunto de bits en la representación del objeto que determina un valor, que es un elemento discreto de una implementación. conjunto definido de valores. 44
donde la nota 44 ( que no es normativa ) dice:
La intención es que el modelo de memoria de C ++ sea compatible con el lenguaje de programación ISO / IEC 9899 C.
Lo más lejos que el borrador del estándar llega a especificar la representación subyacente de bool se encuentra en la sección 3.9.1
:
Los tipos bool, char, char16_t, char32_t, wchar_t y los tipos enteros con signo y sin signo se denominan colectivamente tipos integrales.50 Un sinónimo para tipo integral es tipo entero. Las representaciones de los tipos integrales definirán los valores mediante el uso de un sistema de numeración binario puro.51 [Ejemplo: esta Norma Internacional permite el complemento de 2, el complemento de 1 y las representaciones de magnitud firmada para los tipos integrales. -Final ejemplo]
la sección también dice:
Los valores de tipo bool son verdaderos o falsos.
pero todo lo que sabemos true
de lo true
y lo false
es:
Los literales booleanos son las palabras clave falso y verdadero. Tales literales son valores pricipales y tienen tipo bool.
y sabemos que son convertibles a 0
y 1
:
Un prvalue de tipo bool se puede convertir a un prvalue de tipo int, con falso convirtiéndose en cero y verdadero convirtiéndose en uno.
pero esto no nos acerca a la representación subyacente.
Por lo que puedo decir, el único lugar donde las referencias estándar del valor del bit subyacente real además de los bits de relleno se eliminó a través del informe de defectos 1796: ¿Es todo un bits cero para los caracteres nulos un requisito significativo? :
No está claro que un programa portátil pueda examinar los bits de la representación; en cambio, parece estar limitado a examinar los bits de los números correspondientes a la representación del valor (3.9.1 [basic.fundamental] paragraph 1). Puede ser más apropiado exigir que el valor del carácter nulo se compare con 0 o ''/ 0'' en lugar de especificar el patrón de bits de la representación.
Hay más informes de defectos que tratan los vacíos en el estándar con respecto a lo que es un poco y la diferencia entre el valor y la representación del objeto.
Prácticamente, esperaría que esto funcionara, no lo consideraría seguro ya que no podemos definir esto en el estándar. ¿Necesita cambiarlo, no está claro, claramente tiene un compromiso no trivial involucrado. Entonces, suponiendo que funcione ahora, la pregunta es si consideramos que es probable que rompa con las versiones futuras de varios compiladores, eso es desconocido.
Desde 3.9.1 / 7:
Los tipos bool, char, char16_t, char32_t, wchar_t y los tipos enteros con signo y sin signo se denominan colectivamente tipos integrales. Un sinónimo para tipo integral es tipo entero. Las representaciones de tipos integrales definirán valores mediante el uso de un sistema de numeración binario puro.
Dado esto, no puedo ver ninguna implementación posible de bool
que no represente falso como todos los 0 bits.
¿Está garantizado por la ley? No.
C ++ no dice nada sobre la representación de los valores bool
.
¿Está garantizado por la realidad práctica? Sí.
Quiero decir, si deseas encontrar una implementación en C ++ que no represente booleano false
como una secuencia de ceros, te deseo suerte. Dado que false
debe convertir implícitamente a 0
, y true
debe convertirse implícitamente a 1
, y 0
debe convertirse implícitamente a false
, y no- 0
debe convertirse implícitamente en true
... bueno, sería una tontería implementarlo de otra manera.
Si eso significa que es "seguro" es para que usted decida.
Normalmente no digo esto, pero si estuviera en tu situación, me gustaría dejar pasar esto. Si realmente está preocupado, puede agregar un ejecutable de prueba a su distributable para validar la precondición en cada plataforma de destino antes de instalar el proyecto real.
No. No es seguro (o más específicamente, portátil). Sin embargo, es probable que funcione en virtud del hecho de que su implementación típica:
- use 0 para representar un booleano (de hecho, la especificación C ++ lo requiere)
- generar una matriz de elementos que
memset()
puede manejar.
Sin embargo, las mejores prácticas dictarían usar bool data[32] = {false}
; adicionalmente, esto probablemente liberará al compilador para representar internamente la estructura de manera diferente, ya que el uso de memset()
podría generar una matriz de valores de 32 bytes en lugar de que, digamos, un solo byte 4 que se ajustará perfectamente en el registro promedio de la CPU.