variable valor una turbo tipos longint declaracion datos constantes como asignar delphi pascal freepascal

delphi - valor - tipos de variables en pascal



¿Por qué Delphi y Free Pascal generalmente prefieren un tipo de datos enteros con signo a uno sin firmar? (4)

No soy un novato de Pascal, pero aún no sé hasta ahora por qué Delphi y Free Pascal generalmente declaran parámetros y valores devueltos como enteros con signo, mientras que los veo siempre deben ser positivos. Por ejemplo:

  • Pos() devuelve el tipo de entero. ¿Es posible ser negativo?
  • SetLength() declara el parámetro NewLength como un tipo de entero. ¿Hay una longitud negativa para la cuerda?
  • System.THandle declarado como Longint. ¿Hay un número negativo para las manijas?

Hay muchas decisiones como las de Delphi y Free Pascal. ¿Qué consideraciones estaban detrás de esto?


Bueno, para empezar, THandle está declarado incorrectamente. No está firmado en los encabezados de Windows y debería estarlo en Delphi. De hecho, creo que esto se corrigió en un reciente lanzamiento de Delphi.

Me imagino que la preferencia de firmado sin firmar es en gran parte histórica y no particularmente significativa. Sin embargo, puedo pensar en un ejemplo donde es importante. Considere el bucle for:

for i := 0 to Count-1 do

Si i no tiene firma y el Count es 0, este bucle se ejecuta de 0 a $FFFFFFFF que no es lo que desea. El uso de una variable de bucle entero con signo evita ese problema.

Pascal es víctima de su sintaxis aquí. El bucle C o C ++ equivalente no tiene tal problema

for (unsigned int i=0; i<Count; i++)

debido a la diferencia sintáctica y al uso de un operador de comparación como condición de parada.

Esta también podría ser la razón por la que Length() en una cadena o matriz dinámica devuelve un valor firmado. Y así, por consistencia, SetLength() debería aceptar valores con signo. Y dado que el valor de retorno de Pos() se utiliza para indexar cadenas, también se debe firmar.

Aquí hay otra discusión sobre el desbordamiento de pila del tema: ¿Debo usar enteros sin signo para contar miembros?

Por supuesto, estoy especulando salvajemente aquí. Tal vez no existía un diseño y, simplemente por costumbre, el precedente de usar valores firmados se estableció y se consagró.


En Pascal, Integer (firmado) es el tipo base. Todos los demás tipos de números enteros son subrangos de entero. (Esto no es del todo cierto en los dialectos de Borland, dado el punto largo en TP e int64 en Delphi, pero lo suficientemente cerca).

Una razón importante para eso es que si el resultado intermedio de los cálculos se vuelve negativo, y usted calcula con enteros sin signo, se activarán los errores de verificación de rango, y como la mayoría de los lenguajes de programación antiguos NO asumen enteros de 2 complementos, el resultado (con el rango desactivado) Incluso podría ser corrupto.

El caso THandle es mucho más simple. Delphi no tenía un 32 bits sin firmar hasta el D4, pero solo un cardinal de 31 bits. (dado que el entero sin signo de 32 bits no es un subrango de entero, los ints sin firmar posteriores son un subconjunto de int64, que trasladó el problema a uint64 que solo se agregó en D2010 o algo así)

Por lo tanto, en muchos lugares de los encabezados se usan tipos firmados donde el winapi usa tipos no firmados, probablemente para evitar que el bit 32 se corrompa en esas versiones y se atasque la costumbre.

Pero el caso de winapi es diferente del caso general.

Agregado más tarde Algunas implementaciones de Pascal (y Modula2 / 3) evitan esta trampa al establecer el entero en un tamaño más grande que el tamaño de la palabra, y requieren que todos los tipos numéricos declaren un subintervalo adecuado, como en el programa a continuación.

El primero mantiene la suposición principal de que todo es un subconjunto de entero, y el segundo permite al compilador escalar casi todo de nuevo para que quepa en los registros, especialmente si la CPU tiene algunas operaciones para operaciones mayores que las palabras. (como x86 donde 32-bit * 32-bit mul da un resultado de 64 bits, o puede detectar desbordamientos de tamaño de palabra usando bits de estado (por ejemplo, para generar excepciones de rango para adiciones sin hacer una suma de 2 * de tamaño de palabra completa)

var x : 0..20; y : -10..10; begin // any expression of x and y has a range -10..20


Hay muchas razones para usar enteros con signo, incluso algunos que pueden aplicarse cuando no tiene la intención de devolver un valor negativo.

Imagina que escribo un código que llama a Pos y quiero hacer cálculos con los resultados. ¿Preferiría tener un resultado negativo (Pos(''x'',s)-5) elevar una excepción de control de rango, subdesbordar y convertirse en un número no firmado muy grande de alrededor de 4 mil millones, o pasar a ser negativo, si Pos(''x'',s) devuelve 1 ? Cualquiera de los dos es una fuente de problemas para los nuevos usuarios que rara vez piensan en estos casos, pero la tradición establecida hace mucho tiempo es que al usar los resultados de Integer , es su tarea verificar los resultados negativos y cero y no usarlos como compensaciones de cadena. Hay una ventaja para los programadores avanzados y los principiantes, al usar Integer, y no tener valores "negativos" se convierten en grandes valores sin signo o elevan las excepciones de rango.

En segundo lugar, recuerde que, al comenzar la programación, normalmente se introducen tipos Integer (con signo) mucho antes de que se introduzcan tipos sin signo como Cardinal . Los principiantes a menudo trabajan con funciones como Pos , y tiene sentido usar el tipo que creará el conjunto de efectos secundarios menos hostiles. No hay efectos secundarios negativos por tener un rango más grande que el que necesita absolutamente (el rango que probablemente necesite para Pos es de 1 a la longitud máxima de string-en-delphi). Hay un beneficio cero en Delphi de 32 bits al usar el tipo Cardinal para Pos, y definitivamente hay ALGUNAS desventajas para elegirlo.

Sin embargo, una vez que llegue a Delphi de 64 bits, en teoría podría tener cuerdas MÁS GRANDES de lo que puede soportar un Integer, y mudarse a Cardinal no solucionaría todos sus problemas potenciales. Sin embargo, la posibilidad de que alguien tenga una cadena de más de 2 GB es probablemente nula, y el compilador de 64 bits de Delphi no permite una cadena de más de >2 GB . En mis pruebas, puedo lograr una cadena de casi 1 GB en Delphi de 64 bits. Por lo tanto, el límite de longitud práctica para una cadena Win64 es de aproximadamente mil millones (1073741814) de caracteres, que utilizan casi 2 GB de RAM real. En ese límite, o bien obtengo EIntOverflow o EAccessViolation , y parece que estoy golpeando los errores de la biblioteca de tiempo de ejecución (RTL) de Delphi, no los límites definidos correctamente, por lo que su kilometraje puede variar.


  • Algunas funciones de búsqueda relacionadas con cadenas devuelven -1 cuando no se encuentra nada.
  • Creo que el razonamiento detrás de esto es que MaxInt es de 2 GB, que es el tamaño máximo para cadenas en Delphi de 32 bits. Esto porque un solo proceso puede tener hasta 2 GB de memoria