0xe-0xe
Cの仕様(pdf)の6.4.2や6.4.8を見ると
pp-number: digit . digit pp-number digit pp-number identifier-nondigit pp-number e sign pp-number E sign pp-number p sign pp-number P sign pp-number . identifier-nodigit: nodigit niversal-character-name other implementation-defined characters nondigit: one of [_a-zA-Z]
ってなっているので,"0xe-0xe"はpp-numberとみなされるのが正しいっぽい.コメント欄に書かれてある通りの話だけども.
gccの処理はlibcpp/expr.cの_cpp_parse_exprのあたりを読んでみるとなんとなくわかる(チェックしたバージョンは4.2.1).だいたい以下のようなかんじ.
- cpp_get_tokenでトークンを取得(libcpp/expr.c)
- _cpp_lex_tokenを呼ぶ(libcpp/macro.c)
- _cpp_lex_directを呼ぶ(libcpp/lex.c)
- 最初の文字が[0-9]ならばlex_numberを呼ぶ
- [_a-zA-Z0-9\.]のどれかの文字か,[eEpP][+-]の文字列が続けば,数字っぽいトークンとして文字列をコピー
- 数値とか文字とかだったらeval_token
tccだとエラーが発生しなかったという話なんだけども,最新版(0.9.25)ではエラーがでますね.
$ tcc -v
tcc version 0.9.25
$ cat hoge.c
#include<stdio.h>
int main(void)
{
if (0xe-0xe)
puts("A");
else
puts("B");
return 0;
}
$ gcc hoge.c
hoge.c:4:7: error: invalid suffix "-0xe" on integer constant
$ tcc hoge.c
hoge.c:4: invalid numbertccは構文エラーのチェックが甘いかもしれない.以下のようなコードも通ってしまったし.
$ cat sample.c
int main() {
printf("%d\n", 0x);
}
$ gcc sample.c
sample.c: In function ‘main’:
sample.c:2: warning: incompatible implicit declaration of built-in function ‘printf’
sample.c:2:18: error: invalid suffix "x" on integer constant
$ tcc sample.c
$ ./a.out
0(追記)
やっぱり,tcc-0.9.24のチェックが甘かったっぽい.
tcc-0.9.24とtcc-0.9.25とでparse_number(pp-numberを解析して値を計算する関数)のdiffをとってみると,以下の部分が0.9.25で追加されている
if (ch) error("invalid number\n");
これは本当にpp-numberの最後までスキャンしたかをチェックする.逆に言うと0.9.24ではこのチェックをしていないため,途中までスキャンした文字列がCの数値リテラルとして正しければコンパイルエラーにならないことがある.その結果,以下のようなコードもコンパイルエラーにならないはず.チェックする環境が手元にないのでチェックはしていないけど
int main() { printf("%d\n", 123hoge); printf("%d\n", 0xffhoge); printf("%f\n", 123e-2hoge); }