Pregunta

Actualmente estoy trabajando a través de Acelerado C ++ y han llegado a través de un tema en el ejercicio 2-3.

Una visión general rápida del programa - el programa básicamente toma un nombre, a continuación, muestra un saludo dentro de un marco de asteriscos - es decir ¡Hola! Rodeado enmarcado por * 's.

El ejercicio - En el programa de ejemplo, los autores utilizan const int para determinar el acolchado (espacios en blanco) entre el saludo y los asteriscos. A continuación, le piden al lector, como parte del ejercicio, para pedir al usuario para la entrada como a lo grandes que quieren el relleno sea.

Todo esto parece bastante fácil, sigo adelante preguntar al usuario por dos números enteros (int) y almacenarlos y cambiar el programa para utilizar estos números enteros, la eliminación de las utilizadas por el autor, al compilar aunque me sale el siguiente mensaje de advertencia;

  

Exercise2-3.cpp: 46: advertencia: comparación entre firmado y expresiones entero sin signo

Después de algunas investigaciones, parece ser debido a que los intentos de código para comparar uno de los enteros anteriores (int) a un string::size_type, lo cual está bien. Pero me preguntaba - ¿significa esto que debería cambiar a uno de los números enteros a unsigned int? ¿Es importante indicar expresamente si mis números enteros están firmadas o no?

 cout << "Please enter the size of the frame between top and bottom you would like ";
 int padtopbottom;
 cin >> padtopbottom;

 cout << "Please enter size of the frame from each side you would like: ";
 unsigned int padsides; 
 cin >> padsides;

 string::size_type c = 0; // definition of c in the program
 if (r == padtopbottom + 1 && c == padsides + 1) { // where the error occurs

Por encima son los bits correspondientes del código, el c es de tipo string::size_type porque no sabemos cuánto tiempo podría ser el saludo - pero ¿por qué recibo este problema ahora, cuando el código del autor no consiguió el problema cuando se usan const int? Además - a cualquier persona que haya completado Acelerado C ++ -? ¿Esto será explicado más adelante en el libro

Estoy en el uso de Linux Mint g ++ a través de Geany, si eso ayuda o hace la diferencia (como he leído que podía cuando la determinación de lo que es string::size_type).

¿Fue útil?

Solución

Por lo general, es una buena idea para las variables declarar como unsigned o size_t si se comparan con los tamaños, para evitar este problema. Siempre que sea posible, utilice el tipo exacto que va a hacer la comparación (por ejemplo, std::string::size_type uso cuando se compara con la longitud de un std::string).

compiladores dan advertencias sobre la comparación de firmado y tipos sin signo porque los intervalos de enteros con y sin signo son diferentes, y cuando se comparan entre sí, los resultados pueden ser sorprendentes. Si usted tiene que hacer tal comparación a, usted debe convertir explícitamente uno de los valores de un tipo compatible con la otra, tal vez después de comprobar para asegurarse de que la conversión es válida. Por ejemplo:

unsigned u = GetSomeUnsignedValue();
int i = GetSomeSignedValue();

if (i >= 0)
{
    // i is nonnegative, so it is safe to cast to unsigned value
    if ((unsigned)i >= u)
        iIsGreaterThanOrEqualToU();
    else
        iIsLessThanU();
}
else
{
    iIsNegative();
}

Otros consejos

I tenía el mismo problema ayer de trabajo a través de problema 2-3 en C ++ Accelerated. La clave es cambiar todas las variables se le comparación (utilizando los operadores booleanos) a tipos compatibles. En este caso, eso significa que string::size_type (o unsigned int, pero ya que este ejemplo es utilizar el primer caso, sólo voy a seguir con eso a pesar de que los dos son técnicamente compatibles).

Tenga en cuenta que en su código original que hicieron exactamente esto para el contador C (página 30 en la sección 2.5 del libro), como se ha señalado con razón.

Lo que hace que este ejemplo más complicado es que las diferentes variables de relleno (padsides y padtopbottom), así como todos los contadores, el mosto de también pueden cambiar para string::size_type.

Cómo llegar a su ejemplo, el código que ha publicado terminaría pareciéndose a esto:

cout << "Please enter the size of the frame between top and bottom";
string::size_type padtopbottom;
cin >> padtopbottom;

cout << "Please enter size of the frame from each side you would like: ";
string::size_type padsides; 
cin >> padsides;

string::size_type c = 0; // definition of c in the program

if (r == padtopbottom + 1 && c == padsides + 1) { // where the error no longer occurs

Tenga en cuenta que en condicional anterior, se obtendría el error si no se ha inicializado la variable r como string::size_type en el bucle for. Por lo que necesita para inicializar el bucle usando algo como:

    for (string::size_type r=0; r!=rows; ++r)   //If r and rows are string::size_type, no error!

Así que, básicamente, una vez que se introduce una variable string::size_type en la mezcla, en cualquier momento que desee realizar una operación booleana en ese artículo, todos los operandos debe tener un tipo compatible para que se compile sin advertencias.

La diferencia importante entre enteros con y sin signo es la interpretación del último bit. El último bit en tipos firmados representar el signo del número, es decir: por ejemplo:

0001 es 1 con y sin signo 1001 es -1 firmado y 9 sin signo

(I evitarse todo el tema complemento para claridad de la explicación! Esto no es exactamente cómo enteros se representan en la memoria!)

Se puede imaginar que se hace una diferencia para saber si se compara con -1 o con 9. En muchos casos, los programadores son demasiado perezosos para declarar enteros de conteo como sin signo (hinchazón del para F.I. cabeza circular) Por lo general, no es un problema porque con enteros hay que contar hasta 2 ^ 31 hasta que el bit de signo te muerde. Es por eso que es sólo una advertencia. Debido a que somos demasiado perezosos para escribir 'sin firmar' en lugar de 'int'.

En los rangos extremos, un unsigned int puede llegar a ser más grande que un int.
Por lo tanto, el compilador genera una advertencia. Si está seguro de que esto no es un problema, no dude en echar los tipos al mismo tipo por lo que la advertencia desaparece (el uso de C ++ fundido de manera que sean fáciles de detectar).

Por otra parte, hacer que las variables del mismo tipo para detener el compilador de las protestas.
Es decir, es posible tener un acolchado negativo? Si es así, mantenerlo como un int. De lo contrario, que es mejor usar unsigned int y dejar que el flujo de captura las situaciones en las que el usuario teclea un número negativo.

este biblioteca de cabecera y escritura:

// |notEqaul|less|lessEqual|greater|greaterEqual
if(sweet::equal(valueA,valueB))

y no se preocupan por tamaños firmados / no firmados o diferentes

La cuestión principal es que el hardware subyacente, la CPU, sólo tiene instrucciones para comparar dos valores con signo o comparar los dos valores sin signo. Si pasa la instrucción de comparación sin signo de un valor con signo negativo, se tratan como un número positivo grande. Así, -1, el patrón de bits con todos los bits en (complemento a dos), se convierte en el valor máximo sin firmar para el mismo número de bits.

8 bits: -1 firmado es los mismos bits como 255 sin signo 16 bits: -1 firmado es los mismos bits como 65.535 unsigned etc.

Por lo tanto, si usted tiene el siguiente código:

int fd;
fd = open( .... );

int cnt;
SomeType buf;

cnt = read( fd, &buf, sizeof(buf) );

if( cnt < sizeof(buf) ) {
    perror("read error");
}

encontrará que si la lectura (2) falla debido al descriptor de archivo no válido convertirse (o algún otro error), que CNT se establece en -1. Al comparar a sizeof (BUF), un valor sin signo, la sentencia if () será falsa porque 0xffffffff no menor es que sizeof () algunos (razonable, no inventado para ser el tamaño máximo) estructura de datos.

Por lo tanto, usted tiene que escribir lo anterior, si, para eliminar el aviso firmado / sin firmar como:

if( cnt < 0 || (size_t)cnt < sizeof(buf) ) {
    perror("read error");
}

Esto sólo habla en voz alta a los problemas.

1.  Introduction of size_t and other datatypes was crafted to mostly work, 
    not engineered, with language changes, to be explicitly robust and 
    fool proof.
2.  Overall, C/C++ data types should just be signed, as Java correctly
    implemented.

Si tiene valores tan grandes que no se puede encontrar un tipo de valor con signo que las obras, que están utilizando demasiado pequeño de un procesador o demasiado grande de una magnitud de los valores en el idioma de su elección. Si, al igual que con el dinero, cada digito cuenta, hay sistemas para su uso en la mayoría de los idiomas que se ofrecen infinitas dígitos de precisión. C / C ++ simplemente no hacerlo así, y hay que ser muy explícito sobre todo alrededor de los tipos como se menciona en muchas de las otras respuestas aquí.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top