Does 'sizeof' * really * evaluate to a 'std:: size t'? ¿Puede?


Tome el siguiente pasaje estándar:

[C++11: 5.3.3/6]: El resultado de sizeof y sizeof... es una constante de tipo std::size_t. [Nota: std::size_t se define en la cabecera estándar <cstddef> (18.2). -nota final ]

Ahora:

[C++11: 18.2/6]: El tipo size_t es un tipo entero sin signo definido por la implementación que es lo suficientemente grande como para contener el tamaño en bytes de cualquier objeto.

Concedido, el pasaje no requiere que size_t sea un tipo alias definido con typedef, pero dado que se indica explícitamente que está disponible por el encabezado estándar <cstddef>, creo que podemos tomar como leído que no incluir <cstddef> debería eliminar cualquier garantía de que size_t estará disponible para un programa.

Sin embargo, de acuerdo con esa primera cita, podemos obtener independientemente una expresión de tipo std::size_t.

En realidad podemos demostrar ambos hechos :

int main()
{
    typedef decltype(sizeof(0)) my_size_t;

    my_size_t x   = 0;  // OK
    std::size_t y = 1;  // error: 'size_t' is not a member of 'std'
}

std::size_t no es visible para el programa, pero sizeof(0) todavía nos da uno? ¿En serio?

Por lo tanto, no es correcto decir que 5.3.3/6 es defectuoso , y que en realidad tiene "el mismo tipo que lo que std::size_t resuelve", pero no std::size_t ¿en sí mismo?

Claro, los dos son uno y el mismo si std::size_t es un alias de tipo, pero, de nuevo, en ninguna parte es realmente necesario.

Author: Lightness Races in Orbit, 2013-12-28

5 answers

No confundas el mapa con el territorio.

Los tipos pueden ser nombrados por nombres de tipo. Estos nombres de tipo pueden ser incorporados, pueden ser tipos definidos por el usuario, o incluso podrían ser parámetros template y referirse a múltiples tipos diferentes dependiendo de la instanciación.

Pero los nombres no son los tipos. Claramente standard no exige que todos los tipos tengan nombres the el clásico struct {} es un tipo sin nombre.

std::size_t es un nombre de tipo. Se nombra el tipo que sizeof(expression) devoluciones.

El compilador podría tener un nombre canónico para el tipo -- __size_t sería una manera de tener un único integrado canónica typename.

La norma garantiza en esa cláusula que sea cual sea el tipo de sizeof(expression), una vez que #include <cstddef>, el nombre std::size_t ahora se refiere a ese tipo.

En el estándar, se refieren a tipos por nombres. No dicen "el tipo al que se refiere este nombre de tipo", sino que simplemente dicen "el tipo NAME NOMBRE.". El compilador podría decidir que int es otro nombre para __int_32_fast si quisiera, y el estándar tampoco tendría ninguna objeción.

Lo mismo ocurre con std::nullptr_t y std::initializer_list<Ts> y std::type_info: uso de las variables de esos tipos no siempre requiere que el encabezado que le proporciona un nombre para esos tipos se incluyen en el programa.

Los tipos tradicionales integrados en C/C++ tenían nombres canónicos que no requerían una cabecera. La desventaja es que esto rompe el código existente, como nuevos nombres de tipo en el ámbito global chocar con otros identificadores.

Al tener "tipos sin nombre", donde puede obtener un nombre para ellos mediante la inclusión de un archivo de encabezado, evitamos ese problema.

 45
Author: Yakk - Adam Nevraumont,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-27 23:20:07

El estándar solo exige que el tipo de sizeof(expr) sea el mismo tipo que std::size_t. No hay ningún mandato que usando sizeof(expr) haga que el nombre std::size_t esté disponible y ya que std::size_t solo nombra uno de los tipos integrales incorporados no hay realmente un problema.

 51
Author: Dietmar Kühl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-27 22:56:48

Como yo lo entiendo, este pasaje estándar requiere la siguiente expresión:

typeid(sizeof(0)) == typeid(std::size_t)

Siempre cederá true. Si utiliza el identificador realstd::size_t, ::size_t o cualquier otro alias / typedef será irrelevante siempre y cuando la identidad del tipo, según std::typeinfo::operator==(), se conserve.

El mismo tipo identity issue aparece en otros lugares del idioma. Por ejemplo, en mi máquina de 64 bits el siguiente código no se compila debido a la redefinición de funciones:

#include <cstddef>
void foo(std::size_t x)
{}

void foo(unsigned long x)
{}
 5
Author: rodrigo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-27 23:04:03

Sí.

El tipo producido por sizeof es un tipo entero sin signo; la implementación define cuál es.

Por ejemplo, en alguna implementación en particular, el tipo de una expresión sizeof podría ser unsigned long.

std::size_t, si es un typedef, no es nada más que un nombre alternativo para unsigned long. Así que estas dos declaraciones:

El tipo de sizeof ... es una constante de tipo unsigned long

Y

El tipo de sizeof ... es una constante de tipo std::size_t

Están diciendo exactamente lo mismo para esa implementación. El tipo unsigned long y el tipo std::size_t son del mismo tipo. La diferencia es que este último es preciso para todas las implementaciones (conformes), donde std::size_t podría ser un alias para, por ejemplo, unsigned int o algún otro tipo sin signo.

En lo que respecta al compilador, sizeof produce un resultado de tipo unsigned long; el compilador (a diferencia de la biblioteca de tiempo de ejecución) no necesita tener ningún conocimiento del nombre size_t.

Todo esto asume que std::size_t (o simplemente size_t si estás hablando de C) es un typedef. Eso no se explica en el estándar C o C++. Sin embargo, una implementación puede ajustarse directamente a los requisitos de la norma haciendo size_t un typedef. No creo que haya otra portable manera de satisfacer esos requisitos. (No puede ser una macro o una palabra clave definida por la implementación porque eso infringiría el espacio de nombres del usuario, y una macro no tendría ámbito dentro del espacio de nombres std.) Un compilador podría hacer size_t alguna construcción específica de la implementación que no sea un typedef, pero como un typedef funciona perfectamente bien, no tiene sentido hacerlo. Sería bueno, en mi humilde opinión, si el estándar dijera que size_t es un typedef.

(Un aparte irrelevante: El verdadero problema es que el estándar se refiere al resultado como una "constante". En ISO C, una "constante" es un token, como un literal entero. C++, hasta I saber, no define el sustantivo "constante", pero se refiere a la definición ISO C del término. sizeof ...es una expresión constante ; no es una constante . Llamar al resultado un "valor constante" habría sido razonable.)

 5
Author: Keith Thompson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-27 23:56:05

Es del mismo tipo pero tienes que incluir ese encabezado para usarlo.

 2
Author: user2030677,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-27 22:55:30