Sign in to follow this  
  • entries
  • comments
  • views

Nooks & Crannies

Sign in to follow this  


The observant amongst you will have noticed that it's not Sunday. The even more observant amongst you will have noticed that it's not Sunday and I'm posting a journal entry. The really observant amongst you will notice something odd about this. There is a reason for this. Drum roll please... I wasn't feeling too good last night and had an early night instead of writing this. So it's a day late.

I had another interesting compiler incident at work last week. I had a piece of code performing a number of floating-point operations including some basic trigonometry. It was all working fine until I made a slight modification. After said modification the code worked fine in debug mode but failed with a floating-point stack check error in release mode. Investigations led to much confusion since doing anything differently seemed to result in the code working fine. Even just reading the floating-point operating environment at the start of the function caused the code to stop failing. I hunted through the source code and the generated assembly to see what could be wrong and while the source code looked OK the assembly looked a bit odd. Eventually our lead programmer took a look and after a bit of poking said he'd seen something similar before and it was probably an optimiser bug involving inline assembly (we have our own trig function implementations since our base library is portable across PC and console(s)). If he's right then I'm beginning to lose faith in compilers. That would be two genuine bugs in less than a month!

Outside of work I've been poking around some more obscure parts of the C++ standard. Such knowledge sometimes comes in useful, like when a co-worker was trying to suppress a lint error in a macro and wondering why he couldn't get it to work. Lint errors can be suppressed by adding comments of the form //lint -eXXX but adding that to a macro won't do anything since comments are replaced with a single space before preprocessing.

In the course of my poking I came across the macro examples in Section 16.3.5, Paragraphs 5 & 6, beautifully obscure examples intended to demonstrate as many macro combinations and effects as possible with the minimum quantity of code:
C++ Standard, Section 16.3.5, Paragraph 5
To illustrate the rules for redefinition and reexamination, the sequence
          #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

f(y + 1) + f(f(z)) % t(t(g)(0) + t)(1);
g(x+(3,4)-w) | h 5 & m
results in
     f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1);
f(2 * (2+(3,4)-0,1)) | f(2 * (~5)) & f(2 * (0,1))^m(0,1);

C++ Standard, Section 16.3.5, Paragraph 6
To illustrate the rules for creating character string literals and concatenating tokens, the sequence
          #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 /* from previous #include example */
#define glue(a, b) a ## b
#define xglue(a, b) glue(a, b)
#define HIGHLOW "hello"
#define LOW LOW, ", world"

debug(1, 2);
fputs(str(strncmp("abc\0d", "abc", '\4') /* this goes away */
== 0) str(: @\n), s);
#include xstr(INCFILE(2).h)
glue(HIGH, LOW);
xglue(HIGH, LOW);
results in
     printf("x" "1" "= %d, x" "2" "= %s", x1, x2);
fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s);
#include "vers2.h" (after macro replacement, before file access)
"hello" ", world"
or, after concatenation of the character string literals,
     printf("x1= %d, x2= %s", x1, x2);
fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0: @\n", s);
#include "vers2.h" (after macro replacement, before file access)
"hello, world"
Space around the # and ## tokens in the macro definition is optional.
Just trying to follow through the expansions to verify the result took me a good five minutes. Any errors in transcribing the above excerpts are my own.

I'm also trying to figure out if the following code is valid C++:
int main()
int @ = 1;
return @;

I've not found a compiler that will accept it, but '@' is not in the basic source character set (Section 2.2, Paragraph 1) and the first phase of translation includes:
C++ Standard, Section 2.1, Paragraph 1, excerpt
Any source file character not in the basic source character set (2.2) is replaced by the universal-character-name that designates that character.

And an identifier is defined as:
C++ Standard, Section 2.10
identifier nondigit
identifier digit

one of

_ a b c d e f g h i j k l m
n o p q r s t u v w x y z

one of
0 1 2 3 4 5 6 7 8 9
Anyone wanting to argue for or against the validity of @ as a C++ identifier, speak now or forever hold your peas. (Yes, that was a terrible pun. You should be used to them by now).

Finally, unless anyone has any other recommendations, I'm planning on adding Journal of EasilyConfused to my list of regularly-read GDNet journals, to replace EDI's journal. (Always three there are, a master, an apprentice, and a very talented indie team).

I almost forgot, this week I found myself writing two oddly named functions: consume_hash and consume_carrot. The latter was a typo indirectly caused by the former (No, not for the reasons you're thinking). Who needs drugs when your brain is capable of such nonsense unaided?

Sign in to follow this  


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now