Today I ran into the following error:
Error 1 error C2733: second C linkage of overloaded function '_interlockedbittestandset' not allowed $VCDIR\include\intrin.h 944 Error 2 error C2733: second C linkage of overloaded function '_interlockedbittestandreset' not allowed $VCDIR\include\intrin.h 945
Eeek, what’s going on there? Well, my first instinct was to redefine the name to something else to see what breaks. Turns out that doesn’t help a lot depending on where you do that. The problem appears to be that the two intrinsic functions _interlockedbittestandset
and _interlockedbittestandreset
are declared both in WinNT.h
and in intrin.h
. Actually it’s also “defined” (in quotes because it’s using #pragma intrinsic
) as an intrinsic in WinNT.h
, and we won’t get around this easily, because if we change the name of those intrinsics before including WinNT.h
, the compiler is going to complain that it has no clue what intrinsic it is we want to use:
Warning 1 warning C4163: '_local_interlockedbittestandset' : not available as an intrinsic function $SDKDIR\Include\winnt.h 3124 Warning 2 warning C4163: '_local_interlockedbittestandreset' : not available as an intrinsic function $SDKDIR\Include\winnt.h 3125
Now that is annoying. However, I didn’t want to go for the invasive method of editing one of the SDK headers. Instead I decided to use the powers of the preprocessor to my advantage. The first issue here was to make sure WinNT.h
gets included first. For most Windows code this is a given with Windows.h
providing this prerequisite.
Next I had to include intrin.h
(which contains a convenient #pragma once
) in the main source file which created the mess in the first place. However, in order to mask out the second declaration of the function I had to rename it. That’s where the preprocessor comes in:
#if _MSC_VER >= 1400 // Following 8 lines: workaround for a bug in some older SDKs # pragma push_macro("_interlockedbittestandset") # pragma push_macro("_interlockedbittestandreset") # pragma push_macro("_interlockedbittestandset64") # pragma push_macro("_interlockedbittestandreset64") # define _interlockedbittestandset _local_interlockedbittestandset # define _interlockedbittestandreset _local_interlockedbittestandreset # define _interlockedbittestandset64 _local_interlockedbittestandset64 # define _interlockedbittestandreset64 _local_interlockedbittestandreset64 # include <intrin.h> // to force the header not to be included elsewhere # pragma pop_macro("_interlockedbittestandreset64") # pragma pop_macro("_interlockedbittestandset64") # pragma pop_macro("_interlockedbittestandreset") # pragma pop_macro("_interlockedbittestandset") #endif
Since intrin.h
got introduced with VS 2005, we check for this precondition. Then we save (push_macro
) the values of the _interlockedbittestandset
and _interlockedbittestandreset
defines, if any. Then we rename them and include intrin.h
, thus creating a definition for functions _local_interlockedbittestandset
and _local_interlockedbittestandreset
and then we restore (pop_macro
) the old values of the macros using those function names, just in case.
This could of course be put into a local header, so as to not repeat this every time we need to use WinNT.h
and intrin.h
together in a source file.
Attention: make sure that none of your headers ends up including intrin.h
on its own before the above fix. This will break the fix as Roan found out and remarked in a comment. Sorry for not being more explicit about this requirement before.
Problem solved
Update: Mozilla came up with a subset of my solution here. It won’t work if you make use of those functions, though. Because in this case later references will get renamed according to the macro expansion rules.
// Oliver
PS: the problem also exists for _interlockedbittestandset64
and _interlockedbittestandreset64
(now included in the fix above)
PPS: it should also be possible to throw this last block above the inclusion of WinNT.h
– haven’t tested that, though.
Thanks! It helped me to downgrade one project from vc11 to vc10
Extremely after the fact here, but I had trouble with this solution until I realized that i was including before this code. That was importing intrin.h first, and preventing the fix. I think it’s worth an extra note to put this code before any other dependents of intrin.h; Perhaps first thing is best. But nonetheless, many thanks for the fix, worked like a charm!
Hey Roan, will add a note as per your suggestion.