c++ - resueltos - sentencia for
Interacción inversa sin signo con ciclos for (10)
¿Estás realmente iterando hacia abajo desde un número mayor que std::numeric_limits<int>::max()
? De lo contrario, sugeriría simplemente usar una int
normal como variable de bucle y static_cast
para static_cast
la unsigned
en los lugares de su código que esperan que no esté firmada. De esta forma puede usar la condición intuitiva >= 0
o > -1
y, en general, esperaría que fuera más legible que cualquiera de las alternativas sin firmar.
El static_cast
sería simplemente para decirle al compilador cómo operar en la variable y no tiene implicaciones en el rendimiento.
Quiero que la variable del iterador en un bucle for invierta la iteración a 0 como un unsigned int
, y no puedo pensar en una comparación similar a i > -1
, como lo haría si fuera un signed int
.
for (unsigned int i = 10; i <= 10; --i) { ... }
Pero esto parece muy poco claro, ya que se basa en el desbordamiento numérico del entero sin signo para estar por encima de 10.
Tal vez simplemente no tengo una cabeza clara, pero ¿cuál es una mejor manera de hacer esto ...
Descargo de responsabilidad: este es solo un caso de uso simple, el límite superior de 10 es trivial, podría ser cualquier cosa, y debo ser un unsigned int
.
El siguiente hace lo que quiere:
for (unsigned i = 10; i != static_cast<unsigned>(-1); --i)
{
// ...
}
Esto está perfectamente definido y realmente funciona. La aritmética en los tipos con signo está definida con precisión por el estándar. En efecto:
Desde 4.7 / 2 (con respecto a la conversión a un tipo sin firmar):
Si el tipo de destino no está firmado, el valor resultante es el entero menos sin signo congruente con el entero de origen (módulo 2 ^ n donde n es el número de bits utilizados para representar el tipo sin signo)
y 3.9.1 / 4
Los enteros sin signo, declarados sin signo, obedecerán las leyes del módulo aritmético 2 ^ n donde n es el número de bits en la representación del valor de ese tamaño particular del número entero
Mi patrón para esto es usualmente ...
for( unsigned int i_plus_one = n; i_plus_one > 0; --i_plus_one )
{
const unsigned int i = i_plus_one - 1;
// ...
}
Puede intentar y definir la siguiente macro:
#define for_range(_type, _param, _A1, _B1) /
for (_type _param = _A1, _finish = _B1,/
_step = static_cast<_type>(2*(((int)_finish)>(int)_param)-1),/
_stop = static_cast<_type>(((int)_finish)+(int)_step); _param != _stop; /
_param = static_cast<_type>(((int)_param)+(int)_step))
Ahora puedes usarlo:
for_range (unsigned, i, 10,0)
{
cout << "backwards i: " << i << endl;
}
Se puede usar para iterar hacia atrás y hacia adelante a través de enteros, enteros, y caracteres sin signo:
for_range (char, c, ''z'',''a'')
{
cout << c << endl;
}
enum Count { zero, one, two, three };
for_range (Count, c, zero, three)
{
cout << "forward: " << c << endl;
}
A pesar de su definición incómoda, está optimizado muy bien. Miré desensamblador en VC ++. El código es extremadamente eficiente. No se desanime, pero las tres declaraciones: el compilador producirá solo un ciclo después de la optimización. Incluso puede definir bucles cerrados:
unsigned p[4][5];
for_range (Count, i, zero,three)
for_range(unsigned int, j, 4, 0)
{
p[i][j] = static_cast<unsigned>(i)+j;
}
Obviamente no puede iterar a través de tipos enumerados con espacios.
Puedes usar
for (unsigned int j = n; j-- > 0; ) {}
Se itera desde n-1
hasta 0
.
Puedo pensar que las dos opciones son números fundidos o chamuscados (se puede hacer comparando implícitamente con -1, por ejemplo) o usar la condición de bucle para verificar el desbordamiento de esta manera:
for(unsigned i=10;i>i-1;--i){ } // i = 10, 9, ... , 1
for(unsigned i=10;i+1>i;--i){ } // i = 10, 9, ... , 1,0
Este ciclo continuará hasta que desborde (lo que significa que llegó a cero). Tenga en cuenta que es importante iterar por 1, o puede terminar con un ciclo infinito.
Sólo:
int start = 10;
for(unsigned int iPlus1 = start + 1 ; iPlus1 > 0 ; iPlus1--) {
// use iPlus1 - 1 if you need (say) an array index
a[iPlus1 - 1] = 123; // ...
}
¿No?
Una forma más:
for(unsigned i = n-1; i < n ; --i)
{
// Iterates from n-1 to 0
}
Simillarly para size_t (tipo entero sin signo) usa el mismo truco
for(std::size_t i = n-1; i < n ; --i)
{
// Iterates from n-1 to 0
}
Yo usaría dos variables:
unsigned int start = 10;
for (unsigned int j = 0, i = start; j <= start; ++ j, -- i) {
// ...
}
También puede usar un ciclo while:
unsigned int start = 10;
unsigned int i = start + 1;
while (i --) {
// ...
}
for(unsigned i = x ; i != 0 ; i--){ ...
Y si desea ejecutar el cuerpo del bucle cuando i == 0 y detener después de eso. Simplemente comience con i = x+1;
Por cierto, ¿por qué debo estar sin firmar?