ISO-ANSI C/C++ 预处理器测试文本
http://blog.csdn.net/huyansoft/archive/2009/04/01/4039976.aspx
A test file for my ISO C/C++ PreprocessorCopyright(c) 2008, HuYanAll rights reserved.
Trigraph------------------------------------------------------------------------------------------------------------------------
in normal textint a ??( ??) = ??< 1, 2, 3 ??>; //equivalent to next lineint a [ ] = { 1, 2, 3 };
in preprocessing directives??=define MACRO_TRIGRAPH(a,b) a ??=??= b //equivalent to next line#define MACRO_TRIGRAPH(a,b) a ## b
in comments/* ??= ??) ??! ??( ??' ??> ??/n ??< ??- */ //equivalent to next line/* # ] | [ ^ } /n { ~ */
in backslashch??/ar* s="string ??/literal";
equivalent toch/ar* s="string /literal";
and equivalent tochar* s="string literal";
Backslash------------------------------------------------------------------------------------------------------------------------
in normal textch/ar* s="string /literal";
equivalent tochar* s="string literal";
in preprocessing directives#/defi/ne MACRO_/BACKSLASH/(a,b) a #/# b
equivalent to#define MACRO_BACKSLASH(a,b) a ## b
in comments//a single-/line comment
///a single-line comment
//*a multi-line comment*//
in the end of filenext backslash is unexpected if it is the last character of this file/
next backslash is unexpected if next newline is the end of this file/
Single-line comment-----------------------------------------------------------------------------------------------------------------------
in characters constant and string literal'a//b' //a characters constant, not syntax error"a//b" //4 characters string literal, not syntax error
between tokens (replacement to a space)m=n//**/o //equivalent to m=n , not equivalent to m=n/o
in header name (error)#include <file.h//> //undefined behavior, not equivalent to #include <file.h>#include "file.h//" //undefined behavior, not equivalent to #include <file.h>
attempt defined it as macro (error)#define SINGLE_LINE_COMMENT // SINGLE_LINE_COMMENT abc //error, 'abc' not comment
#define GLUE(x,y) x##yGLUE(/,/) abc //error, 'abc' not comment
Multi-line comment------------------------------------------------------------------------------------------------------------------------
in characters constant and string literal'a//b' //a characters constant, not syntax error"a/**/b" //6 characters string literal, not syntax error
between tokens (replacement to a space)/**/#/**/define/**/MACRO_COMMENT/**/replacement/**/list/**/ //equivalent to next line # define MACRO_COMMENT replacement list
within punctuator or identifier (error)i+/**/+ //equivalent to i+ +, not equivalent to i++#incl/**/ude <file.h> //error, equivalent to #incl ude <file.h>
in header name (error)#include <file.h/**/> //undefined behavior, not equivalent to #include <file.h>#include "file.h/**/" //undefined behavior, not equivalent to #include <file.h>
nesting/*****************************/ //ok/* // */ //ok,a multi-line comment/* /**/ */ //error, multi-line comments do not nest ('*/' found outside of comment)
// /**/ //error, '*/' found outside of comment
//attempt defined it as macro (error)#define BEGIN_COMMENT /*#define END_COMMENT */BEGIN_COMMENT abc END_COMMENT //error, 'abc' not comment
Identifier----------------------------------------------------------------------------------------------------------------------------------
_ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz //an identifier/u1234_/uABCD_/U00001234_/U0000abcd //an identifier (contains universal character names)
Preprocessing operator or punctuator--------------------------------------------------------------------------------------------------------
parsing>>=++++ //three punctuators, '>>=' and two '++'x+++++y //parsed as x ++ ++ + y (although this expression is invalid), not x ++ + ++ y
reserved operator#define delete DELETE //error, 'delete' is an operator in C++, not an identifier
Preprocessing number------------------------------------------------------------------------------------------------------------------------
familiar123L //valid preprocessing number, a long integer.123 //valid preprocessing number, a floating number0123 //valid preprocessing number, a octal number0x123abc //valid preprocessing number, a hexadecimal number3.14e10 //valid preprocessing number3.14e+10 //valid preprocessing number3.14E-10 //valid preprocessing number
definition123.456._.abc.ABC.e+.e-.E+.E- //valid preprocessing number.123.456._.abc.ABC.e+.e-.E+.E- //valid preprocessing number./u1234_/uABCD_/U00001234_/U0000abcd //a preprocessing number (contains universal character names)
+123 //not a preprocessing number-123 //not a preprocessing number123+ //not a preprocessing number123- //not a preprocessing number
importance#define X123 4560X123 //'X123' is not an identifier and will not be expanded, because '0X123' is a preprocessing number
Header name-------------------------------------------------------------------------------------------------------------------------------
parsing#include <file.h>= //'>=' is not a punctuator because <file.h> is a header namea < b && c > d //< b && c > is not a header name#if a < b && c > d //< b && c > is not a header name#endif
matching#include <file.h //error, missing matched separator#include "file.h //error, missing matched quotes#include L"file.h" //error, unexpected 'L'
unexpected characters in header names#include <' / " // /* > //undefined behavior#include " ' / // /* " //undefined behavior
processing before string connecting#define BASE_NAME "file"#define EXTEND_NAME ".h"#include BASE_NAME EXTEND_NAME //equivalent to #include "file" ".h" , but not equivalent to #include "file.txt"
Character constant------------------------------------------------------------------------------------------------------------------------
empty character (error)'' //errorL'' //error
matching' //error, missing matched single-quotesL' //error, missing matched single-quotes'abc/' //error, missing matched single-quotes, /' is only a escape sequenceL'abc/' //error, missing matched single-quotes, /' is only a escape sequence
escape sequences'/a /b /f /n /r /t /v /' /" /? //' //valid escape sequences'/c /d /e / /+' //invalid escape sequences' ? " ' //ok, may represented by ' /? /" '
value range of escape sequences'/400' //error, too large value of octal escape sequence'/377' //okL'/777' //ok
'/x100' //error, too large value of hexadecimal escape sequence'/xff' //okL'/x10000' //error, too large value of escape hexadecimal sequenceL'/xffff' //ok
String literal----------------------------------------------------------------------------------------------------------------------------
empty string"" //okL"" //ok
matching" //error, missing matched quotesL" //error, missing matched quotes"abc/" //error, missing matched quotes, /" is only a escape sequenceL"abc/" //error, missing matched quotes, /" is only a escape sequence
escape sequences"/a /b /f /n /r /t /v /" /" /? //" //valid escape sequences"/c /d /e / /+" //invalid escape sequences" ? ' " //ok, may represented by " /? /' "
value range of escape sequences"/400" //error, too large value of octal escape sequence"/377" //okL"/777" //ok
"/x100" //error, too large value of hexadecimal escape sequence"/xff" //okL"/x10000" //error, too large value of escape hexadecimal sequenceL"/xffff" //ok
Universal character name-----------------------------------------------------------------------------------------------------------------------
within identifier/u1234_/uABCD_/U00001234_/U0000abcd //valid
within character constant'/u1234_/uABCD_/U00001234_/U0000abcd' //valid
within string literal"/u1234_/uABCD_/U00001234_/U0000abcd" //valid
within preprocessing number./u1234_/uABCD_/U00001234_/U0000abcd //valid
value range/u0065_/U00000065 //error, a universal character name cannot designates a basic source character (uncompleted)'/u0065 /U00000065' //error, a universal character name cannot designates a basic source character (uncompleted)"/u0065 /U00000065" //error, a universal character name cannot designates a basic source character (uncompleted)./u0065_/U00000065 //error, a universal character name cannot designates a basic source character (uncompleted)
/u0019_/u007f_/u009f_/U00000019_/U0000007f_/U0000009f //error, a universal character name cannot less than 0x20, or in the range 0x7F-0x9F'/u0019 /u007f /u009f /U00000019 /U0000007f /U0000009f' //error, a universal character name cannot less than 0x20, or in the range 0x7F-0x9F"/u0019 /u007f /u009f /U00000019 /U0000007f /U0000009f" //error, a universal character name cannot less than 0x20, or in the range 0x7F-0x9F./u0019_/u007f_/u009f_/U00000019_/U0000007f_/U0000009f //error, a universal character name cannot less than 0x20, or in the range 0x7F-0x9F
Preprocessing directive and normal text--------------------------------------------------------------------------------------------------------
null directive# //no effect
normal text#define EMPTYEMPTY #include <file.h> //a text line, will expend to #include <file.h> but not a preprocessing directive
#define INCLUDE1 #include <file.h>INCLUDE1 //a text line, will expend to #include <file.h> but not a preprocessing directive
#define INCLUDE2 #includeINCLUDE2 <file.h> //a text line, will expend to #include <file.h> but not a preprocessing directive
directive name#define INCLUDE3 include <file.h>#INCLUDE3 //error, nonexistent directive name
#define INCLUDE4 include#INCLUDE4 <file.h> //error, nonexistent directive name
#define pragma error#pragma "abc" //the directive name is 'pragma' but not 'error', because the replacement was not occured
Source file inclusion---------------------------------------------------------------------------------------------------------------------------
#define MAKE_HEADER(s) #s#include MAKE_HEADER(file.h) //ok, macro expanded, the header name is "file.h"
//#include "stdio.h" //working but warning
//#line __LINE__ "new.h" //next line is error even if current line is reserved#include "test.txt" //error, cannot include itselt, though current file name was modified to "new.h" by last line
#include "b.txt" //begin a recursive inclusion, b.txt and c.txt will include each other
Conditional inclusion---------------------------------------------------------------------------------------------------------------------------
syntax checking in skipped groups#if 0 //checking carefully and responsibly even if in skipped groups "abc //fogot a quotes '/400' //too large value of octal escape sequence #include <d:/file.h> //unexpected '/' character #define PI3.14 //forgot spaces after PI #define MAX(a,a) a>b?a:b //careless spelling of second parameter #define defined otherwise //do not know identifier 'defined' is reserved #line "file.h" 100 //two arguments reversed#elsc //careless spelling, follow lines before #endif will be ignored unecpectly #define PI 3.14 //ignored unecpectly#endif
unreplaced macros#define UNREPLACED something
#ifdef UNREPLACED //UNREPLACED will not be expanded#endif
#ifndef UNREPLACED //UNREPLACED will not be expanded#endif
#if defined(UNREPLACED) //UNREPLACED will not be expanded#elif defined(UNREPLACED) //UNREPLACED will not be expanded#endif
matching#endif //error, missing matched 'if' branch#else //error, missing matched 'if' branch#elif 1 //error, missing matched 'if' branch
#if 0#elif 0#else//#elif 0 //error if this line reserved, 'elif' branch shall not occur after 'else' branch#endif //dismatch if this line is removed
branch testing#define A#ifndef A #ifdef B a if #elif 0 a elif a #elif 1 a elif b #else a else #endif#elif 0 #ifdef b b if #elif 0 b elif a #elif 1 b elif b #else b else #endif#elif 1 #ifdef c c if #elif 0 c elif a #elif 1 c elif b #else c else #endif#else #ifdef d d if #elif 1 d elif a #elif 1 d elif b #else d else #endif#endif
Macro definition-----------------------------------------------------------------------------------------------------------------------------
white separator#define PI3.14 //invalid directive format, forgeting space after macro name#define PI()3.14 //invalid directive format, forgeting space after ')'#define MACRO_MAX (a,b) ((a)>(b)?(a):(b)) //will be defined as object-like macro, not function-like macro
redefinition#define ERR_PARA(a,a) something //error, parameter 'a' redefined
#define OBJECT_LIKE something#define OBJECT_LIKE() something //error, cannot redefine object-like macro as function-like macro
#define FUNCTION_LIKE() something#define FUNCTION_LIKE something //error, cannot redefine function-like macro as object-like macro
#define OBJ_LIKE (1)#define OBJ_LIKE (0) //error, redefine with different token sequence in replacement list
#define FUNC_LIKE(a) something#define FUNC_LIKE(b) something //error, redefine with different parameter list
#define MACRO_CONNECT(a,b,c) a##b##c#define MACRO_CONNECT( a , b , c ) a ## b ## c //ok, the same definition to MACRO_CONNECT (uncompleted)
Macro invocation and replacement-----------------------------------------------------------------------------------------------------------------------------
#define MULTI_ARGS(a,b) b,aMULTI_ARGS //valid text, but not a macro invocation
arguments numberMULTI_ARGS() //warning, not enough argumentsMULTI_ARGS(1,) //valid, the second argument is emptyMULTI_ARGS(,2) //valid, the first argument is emptyMULTI_ARGS(,) //valid, both arguments are emptyMULTI_ARGS(1,2,3,4) //valid, though arguments too much
whites (spaces, tabs and newlines) within argumentsMULTI_ARGS ( //valid, though whites involved 1 , 2 )
quotes matching//MULTI_ARGS(a,b //error, missing matched ')'//MULTI_ARGS( isdigit(32), isdigit(65) //error, missing matched ')'MULTI_ARGS( isdigit(32), isdigit(65) ) //valid, four middle parentheses skippedMULTI_ARGS( MULTI_ARGS(1,2), MULTI_ARGS(3,4) ) //valid, nesting invocation (will expand to 4,3,2,1)MULTI_ARGS( 1, #define PI 3.14 //error, preprocessing directives cannot occur within a macro invocation )
replacement time#define MACROX 2#define MACROY MACROX //MACROX does not replaced to 2 now#undef MACROX#define MACROX 3int i=MACROY; //replacement occurs, MACROY will expanded to 3 but not 2
The # operator (string making)----------------------------------------------------------------------------------------------------------------
definition#define ERR_JIN1(a) # //error, # should be followed by a parameter in the replacement list of a function-like macro (uncompleted)#define ERR_JIN2(a) a#b //error, # should be followed by a parameter in the replacement list of a function-like macro (uncompleted)
whites (spaces, tabs and newlines) within arguments#define MKS(s) #sMKS(abc) //expands to "abc"MKS( abc ) //expands to "abc", whites before the first token and after the last token within the argument is deletedMKS(abc) //expands to "abc", (uncompleted)MKS( a b c ) //expands to "a b c", each white within the argument becomes a single space
arguments substitution#define S1(s) #s#define S2(s) S1(s)#define MYNAME huyanS1( MYNAME ) //expands to "MYNAME"S2( MYNAME ) //expands to "huyan"
#define FORMAT(x) #x "=%d/n",x#define MYNUM 100printf( FORMAT(MYNUM) ) //expands to printf( "MYNUM" "=%d/n",100 ), not printf( "100" "=%d/n",100 )
making valid string literal#define S3(s) #sprintf("%s", S3(a/nb "a/nb" // '//' /n '/n')); //expands to next lineprintf("%s", "a/nb /"a//nb/" // '' /n '//n'"); //not next sick line//printf("%s", "a/nb "a/nb" // '//' /n '/n'"); //error, dismatched quotes
The ## operator (token connection)------------------------------------------------------------------------------------------------------------
definition#define ERR_JINJIN1(a) ## a //error, ## cannot occur at the beginning of the replacement list#define ERR_JINJIN2(a) a ## //error, ## cannot occur at the end of the replacement list
#define hash_hash1 ## //error, cannot define ## to a macro directly#define hash_hash2 # ## # //okhash_hash2 //expands to ##
arguments substitution#define CONNECT(x) I ## x#define CONNECT2(x) CONNECT(x)#define S(a) a#define IS(a) aint I2=5;CONNECT( S(1) ) //expands to IS(1), and further expands to 1CONNECT2( S(2) ) //expands to CONNECT2( 2 ), further expands to CONNECT( 2 ), and last expands to I2
example from ISO C Standard#define hash_hash # ## ##define mkstr(a) # a#define in_between(a) mkstr(a)#define join(c, d) in_between(c hash_hash d)char p[] = join(x, y); //equivalent to char p[] = "x ## y";
Complex macro replacement (rescanning and further replacement)---------------------------------------------------------------------------------
#define MACROS(a) a#define MACROT(b) b*bMACROS ( MACROT ) ( 3 ) //expands to 3*3
int M1=3;#define M1 M2#define M2 M1*M1 //recursive definitionprintf("%d/n",M1); //expands to M1*M1 and output 9
#define Puts(s) printf("%s is ",#s); Puts(s)char translator[]={-70,-6,-47,-27,0};Puts(translator); //expands to printf("%s is","translator"); Puts(translator);
example from ISO C Standard#define X 3#define F(a) F(X * (a))#undef X#define X 2#define G F#define Z Z[0]#define H G(~#define M(a) a(W)#define W 0,1#define T(a) a#define P() int#define Q(x) x#define R(x,y) x ## y#define STR(x) # x
F(y+1) + F(F(Z)) % T(T(G)(0) + T) (1); //expands to F(2 * (y+1)) + F(2 * (F(2 * (Z[0])))) % F(2 * (0)) + T(1);G(X+(3,4)-W) | H 5) & M(F)^M(M); //expands to F(2 * (2+(3,4)-0,1)) | F(2 * (~ 5)) & F(2 * (0,1))^M(0,1);P() i[Q()] = { Q(1), R(2,3), R(4,), R(,5), R(,) }; //expands to int i[] = { 1, 23, 4, 5, };char c[2][6] = { STR(hello), STR() }; //expands to char c[2][6] = { "hello", "" };
#define Str(s) # s#define Xstr(s) Str(s)#define Debug(s, t) printf("x" # s "= %d, x" # t "= %s", x ## s, x ## t)#define INCFILE(n) vers ## n#define Glue(a, b) a ## b#define Xglue(a, b) Glue(a, b)#define HIGHLOW "hello"#define LOW LOW ", world"
Debug(1, 2); //expands to printf("x" "1" "= %d, x" "2" "= %s", x1, x2);fputs(Str(strncmp("abc/0d", "abc", '/4') == 0) Str(: @/n), s); //expands to fputs("strncmp(/"abc//0d/", /"abc/", '//4') == 0" ": @/n",s);#include Xstr(INCFILE(2).h) //expands to #include "vers2.h"Glue(HIGH, LOW); //expands to "hello";Xglue(HIGH, LOW) //expands to "hello" ", world"
Macro with variable arguments-----------------------------------------------------------------------------------------------------------------------
definition#define ERR_VAM1 __VA_ARGS__ //error, unexpected __VA_ARGS__ in the replacement list of normal macro#define ERR_VAM2(a,b,c) __VA_ARGS__ //error, unexpected __VA_ARGS__ in the replacement list of normal macro#define ERR_VAM3(a,b,c,...) a,b,c //warning, missing __VA_ARGS__ in the replacement list of variable arguments macro
#define ERR_VAM4(__VA_ARGS__) something //error, the parameter cannot be __VA_ARGS__#define ERR_VAM5(__VA_ARGS__,...) __VA_ARGS__ //error, the parameter cannot be __VA_ARGS__
#define __VA_ARGS__ otherwise //error, the identifier '__VA_ARGS__' is reserved#undef __VA_ARGS__ //error, the identifier '__VA_ARGS__' is reserved
#define VAM1(...) __VA_ARGS__ //ok#define VAM2(a,b,c,...) __VA_ARGS__ //ok
arguments substitution#define VAM3(...) #__VA_ARGS__VAM3() //expands to ""VAM3(1) //expands to "1"VAM3(a,b,c) //expands to "a,b,c"
#define VAM4(a,b,...) a b #__VA_ARGS__VAM4(1) //warning, not enough argumentsVAM4(1,2) //expands to 1 2 ""VAM4(1,2,3,4,5) //expands to 1 2 "3,4,5"VAM4( ((a), (b)), ((c), (d)), ((e),(f)), ((g),(h)) ) //expands to ((a), (b)) ((c), (d)) "((e),(f)), ((g),(h))"
example from ISO C Standard#define Debug2(...) fprintf(stderr, __VA_ARGS__)#define Showlist(...) puts(#__VA_ARGS__)#define Report(test, ...) ((test)?puts(#test):printf(__VA_ARGS__))
Debug2("Flag"); //expands to fprintf(stderr, "Flag" );Debug2("x = %d/n", x); //expands to fprintf(stderr, "x = %d/n", x );Showlist(The first, second, and third items.); //expands to puts( "The first, second, and third items." );Report(x>y, "x is %d but y is %d", x, y); //expands to ((x>y)?puts("x>y"):printf("x is %d but y is %d", x, y));
Predefined macro names and reserved identifiers------------------------------------------------------------------------------------------------
following predefined macros will be expanded__DATE____FILE____LINE____STDC____STDC_HOSTED____STDC_VERSION____TIME__
redefine and undefine (error)#define __DATE__ otherwise //error, cannot redefine predefined macros#define defined otherwise //error, the identifier 'defined' is reserved
#undef __DATE__ //error, cannot undefine predefined macros#undef defined //error, the identifier 'defined' is reserved
Line control-----------------------------------------------------------------------------------------------------------------------------------
//#line 100 //set next line number to 100//#line 200 "file1.h" //set next line number to 200 and current file name to "file1.h"
expanded macro arguments#define LINE_NUMBER1 300//#line LINE_NUMBER1 //set next line number to 300 (the macro LINE_NUMBER1 expanded)
#define LINE_NUMBER2 400//#line LINE_NUMBER2 "file2.h" //set next line number to 400 and current file name to "file2.h"
#define FILE_NAME "file3.h"//#line 500 FILE_NAME //set next line number to 500 and current file name to "file3.h"
#define LINE_FILE 600 "test.h"//#line LINE_FILE //set next line number to 600 and current file name to "test.h"
arguments format#line 0 //error, the line number cannot less than 1#line 2147483648 //error, the line number cannot more than 2147483647#line +100 //error, the line number need not prefixed by '+' or '-'#line "file.h" 100 //error, the first argument shall be a number (after macro replacement)#line 100 L"file.h" //error, the file name need not prefixed by 'L' (cannot be wide string literal)//#line 100 "file.h/" //error, missing matched quotes, the /" is only a escape sequence
counting of line number//#line 100 //set next line number to 100, but next broken '__LINE__' will expands to 101__LINE/__ ;
Error directive------------------------------------------------------------------------------------------------------------------------------
//#error //stop preprocessing//#error message1 //stop preprocessing and output 'message1'
expanded macro arguments#define MESSAGE2 message2//#error MESSAGE2 //macro expanded, stop preprocessing and output 'message2'
#define MAX_VALUE 100//#error the "MAX_VALUE" cannot more than MAX_VALUE //stop preprocessing and output 'the "MAX_VALUE" cannot more than 100'
Pragma directive-----------------------------------------------------------------------------------------------------------------------------
#pragma some_instructions //valid, but all #pragma directives will be ignored and removed
_Pragma operator (uncompleted)_Pragma ("string literal") //it will regard as normal text
[The End]