English 中文(简体)
C++ throwing compilation error on sizeof() comparison in preprocessor #if
原标题:

I have this which does not compile with the error "fatal error C1017: invalid integer constant expression" from visual studio. How would I do this?

template <class B>
A *Create()
{
  #if sizeof(B) > sizeof(A)
  #error sizeof(B) > sizeof(A)!
  #endif
  ...
}
最佳回答

The preprocessor does not understand sizeof() (or data types, or identifiers, or templates, or class definitions, and it would need to understand all of those things to implement sizeof).

What you re looking for is a static assertion (enforced by the compiler, which does understand all of these things). I use Boost.StaticAssert for this:

template <class B>
A *Create()
{
  BOOST_STATIC_ASSERT(sizeof(B) <= sizeof(A));
  ...
}
问题回答

Preprocessor expressions are evaluated before the compiler starts compilation. sizeof() is only evaluated by the compiler.

You can t do this with preprocessor. Preprocessor directives cannot operate with such language-level elements as sizeof. Moreover, even if they could, it still wouldn t work, since preprocessor directives are eliminated from the code very early, they can t be expected to work as part of template code instantiated later (which is what you seem to be trying to achieve).

The proper way to go about it is to use some form of static assertion

template <class B>
A *Create()
{
  STATIC_ASSERT(sizeof(B) <= sizeof(A));
  ...
}

There are quite a few implementations of static assertions out there. Do a search and choose one that looks best to you.

sizeof() cannot be used in a preprocessor directive.

The preprocessor runs before the compiler (at least logically it does) and has no knowledge of user defined types (and not necessarily much knowledge about intrinsic types - the preprocessor s int size could be different than the compiler targets.

Anyway, to do what you want, you should use a STATIC_ASSERT(). See the following answer:

With a STATIC_ASSERT() you ll be able to do this:

template <class B>
A *Create()
{
    STATIC_ASSERT( sizeof(A) >= sizeof( B));
    return 0;
}

This cannot be accomplished with pre-processor . The pre-processor executes in a pass prior to the compiler -- therefore the sizes of NodeB and Node have not yet been computed at the time #if is evaluated.

You could accomplish something similar using template-programming techniques. An excellent book on the subject is Modern C++ Design: Generic Programming and Design Patterns Applied, by Andrei Alexandrescu.

Here is an example from a web page which creates a template IF statement.

From that example, you could use:
IF< sizeof(NodeB)<sizeof(Node), non_existing_type, int>::RET i;

which either declares a variable of type int or of type non_existing_type. Assuming the non-existing type lives up to its name should the template IF condition evaluate as true, a compiler error will result. You can rename i something descriptive.

Using this would be "rolling your own" static assert, of which many are already available. I suggest you use one of those after playing around with building one yourself.

If you are interested in a compile time assert that will work for both C and C++, here is one I developed:

#define CONCAT2(x, y)              x ## y
#define CONCAT(x, y)               CONCAT2(x, y)

#define COMPILE_ASSERT(expr, name)     
    struct CONCAT(name, __LINE__) { char CONCAT(name, __LINE__) [ (expr) ? 1 : -1 ]; }

#define CT_ASSERT(expr)  COMPILE_ASSERT(expr, ct_assert_)

The to how this works is that the size of the array is negative (which is illegal) when the expression is false. By further wrapping that in a structure definition, this does not create anything at runtime.

This has already been explained, but allow me to elaborate on why the preprocessor can not compute the size of a structure. Aside from the fact that this is too much to ask of a simple preprocessor, there are also compiler flags that affect the way the structure is laid out.

struct X { short a; long b; };

this structure might be 6 bytes or 8 bytes long, depending on whether the compiler was told to 32-bit align the "b" field, for performance reasons. There s no way the preprocessor could have that information.

Using MSVC, this code compiles for me:

const int cPointerSize = sizeof(void*);
const int cFourBytes = 4;`

#if (cPointerSize == cFourBytes)
    ...

however this (which should work identically) does not:

#if ( sizeof(void*) == 4 ) ...

i see many people say that sizeof cannot be used in a pre-processor directive, however that can t be the whole story because i regularly use the following macro:

#define STATICARRAYSIZE(a) (sizeof(a)/sizeof(*a))

for example:

#include <stdio.h>

#define STATICARRAYSIZE(a) (sizeof(a)/sizeof(*a))

int main(int argc, char*argv[])
{
        unsigned char chars[] = "hello world!";
        double        dubls[] = {1, 2, 3, 4, 5};

        printf("chars num bytes: %ld, num elements: %ld.
" , sizeof(chars), STATICARRAYSIZE(chars));
        printf("dubls num bytes: %ld, num elements: %ld.
" , sizeof(dubls), STATICARRAYSIZE(dubls));
}

yields:

orion$ ./a.out 
chars num bytes: 13, num elements: 13.
dubls num bytes: 40, num elements: 5.

however

i, too, cannot get sizeof() to compile in a #if statement under gcc 4.2.1. eg, this doesn t compile:

#if (sizeof(int) == 2)
#error uh oh
#endif

any insight would be appreciated.





相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?

热门标签