2012-01-17 8 views
6

Más específicamente, qué es lo mismo typedef 'd con varios nombres diferentes en muchos casos, y por qué typedef tipos de puntero (oscureciendo la lógica a veces)?¿Por qué todo está en el tipo de API de Windows definido?

Por ejemplo:

typedef const WCHAR *LPCWSTR, *PCWSTR;

¿Cuál es el punto de eso?

+4

No conozco los detalles completos de todo, pero pienso en los días de 16 bits con Windows 3.1. Había dos tipos diferentes de punteros en ese momento, punteros cercanos y lejanos. Definieron tipos de puntero para cada uno ('PCWSTR' y' LPCWSTR' respectivamente) para una interfaz uniforme. Debido a la compatibilidad con versiones anteriores que apuntaba Microsoft, nos quedamos con ambos tipos de API debido a esto. –

+1

La verdadera pregunta es, ¿por qué tipean otros tipos de punteros que no tienen el historial del puntero lejano detrás de ellos? Tales como HANDLE, HWND, HINSTANCE etc. Hasta donde yo sé, no hay una respuesta racional a esa pregunta. – Lundin

+2

@Lundin: HANDLE, HWND y otros no son en realidad punteros: son identificadores opacos que son privados de Windows (USER, GDI, KERNEL). Detrás de escena, en realidad pueden usarse como índices en tablas internas o similares. Se tipifican como nulos * específicamente para dejar en claro que solo se deben pasar como están y el código no debe intentar interpretarlos (por ejemplo, haciendo aritmética sobre ellos), lo cual sería fácil de hacer por accidente si fueron decir int valores); un propósito diferente de lo que está sucediendo con los typedefs en el qu de arriba. – BrendanMcK

Respuesta

7

La razón no es tanto PCWSTR y LPCWSTR es que en la antigüedad había una diferencia. LPCWSTR solía ser const WCHAR FAR *.

4

Creo que uno de los objetivos principales de este diseño es permitir que los tipos de las funciones que sirven como documentación de su propósito y formatos de datos esperados.

+0

¿Cuál es la diferencia entre 'LP' y' P' en 'typedef's para tipos de puntero? Quiero decir, más arriba vemos una instancia en la que están 'typedef'd a lo mismo ... –

+5

Podría estar equivocado en esto, pero creo que es un artefacto histórico de Windows de 16 bits, donde tienes tanto punteros como 'long punteros'. Entonces eran tipos separados, pero ahora solo se necesita 1 tipo. Ambos son compatibles para compatibilidad con versiones anteriores. –

18

De hecho, hay algunas cosas diferentes pasando aquí:

  • En primer lugar los punteros cerca/lejos: En la época de Win16, que tenía cerca y punteros; casi punteros eran básicamente solo desplazamientos de 16 bits, por lo que solo podían referirse a objetos dentro de los 64 k del puntero de datos predeterminado de una aplicación (DS o registro del segmento de datos), pero eran pequeños y rápidos; mientras que un "puntero lejano" más grande o un puntero largo consistía tanto de segmento como de desplazamiento, por lo que podría referirse a cualquier cosa dentro del espacio de direcciones de 1M. Cuando apareció el 386, todo este segmento: el negocio de compensación finalmente desapareció, y todos los punteros eran solo direcciones de 32 bits en espacios de direcciones planos de 32 bits. Y es por eso que hay versiones P ... y LP ...

  • por qué utilizar los typedefs en primer lugar? Es solo una conveniencia o taquigrafía: escribir "LPSTR" es más conveniente que "const char far *". Pero también se convierte en un modismo reconocible: ves LPSTR y sabes de inmediato cómo Windows maneja las cadenas en su API.

  • También hay una abstracción pasando aquí: Windows generalmente define sus propias versiones de los tipos y las utiliza en lugar de las versiones C. Por lo tanto, las API de Windows usan DWORD en lugar de int, o VOID en lugar de nulo. Esto fue necesario para tapar algunos agujeros en C en ese momento, no había bool, por lo que al introducir BOOL se evitó que diferentes API utilizaran diferentes tipos para representar valores booleanos (por ejemplo, char vs int). También, en cierta medida, hizo que la API de Windows fuera independiente de una implementación de C subyacente: C no requiere que int sea un tamaño específico: podría ser de 16 bits o 32 bits, según el compilador. Pero para una API de sistema operativo, es importante especificar estas cosas exactamente. Por lo tanto, en lugar de utilizar int o long, Windows utiliza INT y LONG, que luego define según sea necesario y typedefs a cualquier tipo de C subyacente que haga el trabajo real.

  • Por último, algunos de estos son en realidad typedefs haciendo alusión a usos específicos más allá de simplemente escribir información. BOOL e INT son typedef'd como int, pero está claro que un parámetro API especificado como BOOL se usará en un sentido VERDADERO/FALSO, no como un valor entero. (Recuerde que esto es anterior al tipo 'bool'.) Del mismo modo, BYTE - que es char sin signo - sugiere que un parámetro se va a utilizar realmente como un valor numérico de 8 bits en lugar de como un carácter alfanumérico o de símbolo. Y LPSTR indica que se espera que el valor sea una cadena terminada en NUL, en lugar de solo apuntar a valores de caracteres arbitrarios. BSTR y LPWSTR tienen el mismo typedef subyacente, ambos son WCHAR *, pero los BSTR tienen un prefijo de longitud, por lo que deben asignarse con la API SysAllocString. Tener un typedef separado aquí ayuda a mantener los dos requisitos separados de código y documento API: si ves una API que toma un BSTR como parámetro, entonces sabes que no puedes simplemente pasar una cadena ancha, aunque el tipo subyacente sea el mismo, existen requisitos adicionales para ese parámetro.

Cuestiones relacionadas