2010-02-03 11 views
7

Estoy trabajando en un proyecto en el que tengo muchas cadenas constantes formadas por concatenación (números, etc.).¿Cómo convertir cadenas concatenadas a wide-char con el preprocesador C?

Por ejemplo, tengo una macro LOCATION que formatea __FILE__ y __LINE__ en una cadena que permita saber dónde estoy en el código, al imprimir mensajes o errores:

#define _STR(x) # x 
#define STR(x)  _STR(x) 
#define LOCATION __FILE__ "(" STR(__LINE__) ")" 

es así, esto formatee una ubicación como "file.cpp (42)". El problema es cuando intento convertir el resultado a una amplia cadena:

#define _WIDEN(x) L ## x 
#define WIDEN(x) _WIDEN(x) 
#define WLOCATION WIDEN(LOCATION) 

Esto funciona muy bien con GCC, y los resultados en L "file.cpp (42)" ser insertado en mi código. Sin embargo, cuando se trata esto con MSVC++ (utilizando Visual C++ 2008 Express), me sale un error:

error: Concatenating wide "file.cpp" with narrow "(" 

entiendo que el L prefijo se agrega sólo para el primer término de mi expresión. También he intentado esto:

#define _WIDEN(x) L ## #x 

¿Qué "obras", sino que da la cadena L"\"file.cpp\" \"(\" \"42\" \")\"" que obviamente no es muy conveniente (y no lo que busco), sobre todo teniendo en cuenta que esta macro es simple en comparación con otra macros.

Entonces, mi pregunta es: ¿cómo puedo hacer que se aplique a la expresión completa en MSVC++, para que pueda obtener el mismo resultado que obtengo con GCC? Preferiría no crear una segunda cadena con tokens de ancho total, porque tendría que mantener dos macros para cada uno, lo que no es muy conveniente y puede provocar errores. Además, también necesito la versión angosta de cada cadena, por lo que el uso de cadenas de todo el ancho tampoco es una opción, desafortunadamente.

Respuesta

11

De acuerdo con el estándar C (aka "ISO-9899: 1999" también conocido como "C99"), Visual C está equivocado y gcc es correcto. Los estados estándar, sección 6.4.5/4:

En la fase de traducción 6, las secuencias de caracteres multibyte especificadas por cualquier secuencia de caracteres adyacentes y tokens literales de cadena ancha se concatenan en una única secuencia de caracteres multibyte. Si alguno de los tokens son tokens literales de cadena ancha, la secuencia de caracteres multibyte resultante se trata como un literal de cadena ancha; de lo contrario, se trata como un literal de cadena de caracteres.

Para que pueda presentar una queja. Podría decirse que la versión anterior del estándar C (también conocido como "C89", también conocido como "C90", también conocido como "ANSI C") no obligaba a fusionar cadenas amplias con cadenas no anchas. Aunque C99 tiene ahora más de diez años, parece que Microsoft no tiene interés en hacer que su compilador de C se conforme. Algunos usuarios han informado que pueden acceder a algunas características "C99" al compilar el código C como si fuera código C++, porque C++ incluye estas características, y para C++, Microsoft hizo un esfuerzo. Pero esto no parece extenderse al preprocesador.

En el dialecto C89, creo que lo que estás buscando no es posible (de hecho estoy bastante seguro de ello, y como he escrito mi propio preprocesador, creo que sé de lo que estoy hablando). Pero se podría añadir un parámetro adicional y propagarla:

#define W(x)   W_(x) 
#define W_(x)   L ## x 
#define N(x)   x 
#define STR(x, t)  STR_(x, t) 
#define STR_(x, t) t(#x) 

#define LOCATION_(t) t(__FILE__) t("(") STR(__LINE__, t) t(")") 
#define LOCATION  LOCATION_(N) 
#define WLOCATION  LOCATION_(W) 

que deben trabajar en ambos gcc y Visual C (al menos, a mí me funciona, utilizando Visual C 2005).

Nota al margen: no debe definir macros con un nombre que comience con un guión bajo. Estos nombres están reservados, por lo que al usarlos podría chocar con algunos nombres utilizados en los encabezados del sistema o en versiones futuras del compilador. En lugar de _WIDEN, use WIDEN_.

+0

Eso funciona, aunque es una sintaxis incómoda y tiene muchos gastos ... pero funciona y no tengo que mantener varias macros. Con suerte, Microsoft actualizará su preprocesador para admitir más características C99, las cosas serían mucho más simples de esta manera. Gracias! –

1

para concatenar dos cadenas literales de ancho se puede utilizar

L"wide_a" L"wide_b" 

Así se podría definir

#define WLOCATION WIDEN(__FILE__) L"(" WIDEN(STR(__LINE__)) L")" 

(Nota: no probados en MSVC++)

+1

Eso funcionaría, pero esa macro es sólo uno de muchos, y prefiero definir sólo una vez y no tener que mantener dos copias (ancho y angosto) de cada macro, especialmente si las edito un día. Podría ser difícil mantenerlo, aunque debo admitir que ¡funcionaría! –

0

Sólo mediante una amplia cadena vacía literal debería funcionar:

#define WLOCATION L"" __FILE__ "(" STR(__LINE__) ")" 
Cuestiones relacionadas