C_ASSERT doesn't work in C files

Not sure if this is the right place to post…

C_ASSERT works in .cpp but not always in .c files. The reason is its
definition (from ntdef.h):

#define C_ASSERT(e) typedef char C_ASSERT[(e)?1:-1]

From what I understand, because C requires all declarations to be at the
beginning of scope, you can’t have the following in a .c file (though it
works in .cpp):

void f()
{
int x = 0;
C_ASSERT(x==0); /* this works */

x = 14;
C_ASSERT(x==14); /* this doesn’t */
}

… and the compile fails with a truly obscure error: C2143: syntax error :
missing ‘;’ before ‘type’

The problem seems to be solved if we wrap the definition in braces:

#define C_ASSERT(e) { typedef char C_ASSERT[(e)?1:-1]; }

Just thought I’d mention it, since it’s a useful feature but not usable in
its present state.

C_ASSERT is mostly used to check things like sizeof(struct_x) ==
sizeof(struct_y) which is generally done around the type definition.

-p

From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Alexandru Pojoga
Sent: Thursday, January 04, 2007 7:38 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] C_ASSERT doesn’t work in C files

Not sure if this is the right place to post…

C_ASSERT works in .cpp but not always in .c files. The reason is its
definition (from ntdef.h):

#define C_ASSERT(e) typedef char C_ASSERT[(e)?1:-1]

From what I understand, because C requires all declarations to be at the
beginning of scope, you can’t have the following in a .c file (though it
works in .cpp):

void f()
{
int x = 0;
C_ASSERT(x==0); /* this works */

x = 14;
C_ASSERT(x==14); /* this doesn’t */
}

… and the compile fails with a truly obscure error: C2143: syntax
error : missing ‘;’ before ‘type’

The problem seems to be solved if we wrap the definition in braces:

#define C_ASSERT(e) { typedef char C_ASSERT[(e)?1:-1]; }

Just thought I’d mention it, since it’s a useful feature but not usable
in its present state.
— Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256 To unsubscribe, visit the
List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Oops, slipped my keyboard. I meant something like:

void f()
{
int x = 0;
C_ASSERT(sizeof(int)==4); /* this works */

x = 14;
C_ASSERT(sizeof(int)==4); /* this doesn’t */
}

The point still stands, though – C_ASSERT in its current form can’t be
dropped anywhere in C code.

You do realize that C_ASSERT is a static (compile-time) assertion, and not a runtime assertion? Which means that most uses of C_ASSERT are outside of function scopes. Even if it is necessary to use within a function, you should be able to move it to the beginning of the function, since C_ASSERT is not intended to check the results of statements (runtime effects).

C_ASSERT is not intended to be a replacement for ASSERT.


From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Alexandru Pojoga
Sent: Friday, January 05, 2007 12:12 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] C_ASSERT doesn’t work in C files

Oops, slipped my keyboard. I meant something like:

void f()
{
int x = 0;
C_ASSERT(sizeof(int)==4); /* this works */

x = 14;
C_ASSERT(sizeof(int)==4); /* this doesn’t */
}

The point still stands, though – C_ASSERT in its current form can’t be dropped anywhere in C code.
— Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256 To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

A good catch! thanks!
– Pavel

“Alexandru Pojoga” wrote in message news:xxxxx@ntdev…
> Not sure if this is the right place to post…
>
> C_ASSERT works in .cpp but not always in .c files. The reason is its
> definition (from ntdef.h):
>
> #define C_ASSERT(e) typedef char C_ASSERT [(e)?1:-1]
>
> From what I understand, because C requires all declarations to be at the
> beginning of scope, you can’t have the following in a .c file (though it
> works in .cpp):
>
> void f()
> {
> int x = 0;
> C_ASSERT(x==0); /* this works /
>
> x = 14;
> C_ASSERT(x==14); /
this doesn’t */
> }
>
> … and the compile fails with a truly obscure error: C2143: syntax error :
> missing ‘;’ before ‘type’
>
> The problem seems to be solved if we wrap the definition in braces:
>
> #define C_ASSERT(e) { typedef char C_ASSERT [(e)?1:-1]; }
>
> Just thought I’d mention it, since it’s a useful feature but not usable in
> its present state.
>

But it isn't really a "good catch" because it would break C_ASSERT.

C_ASSERT is intended for use outside of function scope like so:

**********************
Struct foo {
...
};

Struct bar {
...
};

C_ASSERT(sizeof(foo) >= sizeof(bar);
***********************

As is C_ASSERT is a global type definition which is fine in C.

With {}'s added, C_ASSERT becomes a global block of undefined type. C
won't allow you to have

{
Anything
}

At global scope without a keyword to indicate what the following block
contains. So it would

But it's not really a good catch. This change would break C_ASSERT for
its intended usage.

Take the following C file:


#define C_ASSERT(e) typedef char C_ASSERT[(e)?1:-1]
#define C_ASSERT_WITH_BRACES(e) {C_ASSERT(e)}

struct foo {
int i;
};

struct bar {
int i;
int j;
};

C_ASSERT(sizeof(struct bar) > sizeof(struct foo));
C_ASSERT_WITH_BRACES(sizeof(struct bar) > sizeof(struct foo));

Compiling this with cl.exe gives the following error:

C:\WinDDK\6000\src\umdf\usb\fx2_driver>cl foo.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.220
for 80x86

Copyright (C) Microsoft Corporation. All rights reserved.

foo.c
foo.c(14) : error C2449: found '{' at file scope (missing function
header?)
foo.c(14) : error C2059: syntax error : '}'
foo.c(14) : fatal error C1004: unexpected end-of-file found

you can't have a naked { } block at global scope.

-p

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Pavel A.
Sent: Friday, January 05, 2007 8:27 AM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] C_ASSERT doesn't work in C files

A good catch! thanks!
-- Pavel

"Alexandru Pojoga" wrote in message
news:xxxxx@ntdev...
> Not sure if this is the right place to post...
>
> C_ASSERT works in .cpp but not always in .c files. The reason is its
> definition (from ntdef.h):
>
> #define C_ASSERT(e) typedef char C_ASSERT [(e)?1:-1]
>
> From what I understand, because C requires all declarations to be at
the
> beginning of scope, you can't have the following in a .c file (though
it
> works in .cpp):
>
> void f()
> {
> int x = 0;
> C_ASSERT(x==0); /* this works /
>
> x = 14;
> C_ASSERT(x==14); /
this doesn't */
> }
>
> ... and the compile fails with a truly obscure error: C2143: syntax
error :
> missing ';' before 'type'
>
> The problem seems to be solved if we wrap the definition in braces:
>
> #define C_ASSERT(e) { typedef char C_ASSERT [(e)?1:-1]; }
>
> Just thought I'd mention it, since it's a useful feature but not
usable in
> its present state.
>

---
Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

To unsubscribe, visit the List Server section of OSR Online at
ListServer/Forum

> you can’t have a naked { } block at global scope.

Thanks for that, point taken. So you’re either a good C citizen and declare everything at beginning of scope, or use C++ and go crazy with C_ASSERTS :slight_smile:

Or use C_ASSERTs where it makes sense (where you’re really checking compile time behavior) and then use the regular ASSERT macro for any runtime checks you need.

Of course ASSERTs aren’t error handling so you may actually want to be dealing with some of the error cases you find rather than asserting.

-p

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Friday, January 05, 2007 2:30 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] C_ASSERT doesn’t work in C files

you can’t have a naked { } block at global scope.

Thanks for that, point taken. So you’re either a good C citizen and declare everything at beginning of scope, or use C++ and go crazy with C_ASSERTS :slight_smile:


Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

wrote in message news:xxxxx@ntdev…
>> you can’t have a naked { } block at global scope.
>
> Thanks for that, point taken. So you’re either a good C citizen and declare everything at beginning of scope, or use C++ and
> go crazy with C_ASSERTS :slight_smile:

Ok. Let it be two good catches :slight_smile:

–P

I still think you’re missing the point (or someone is) about C_ASSERT vs ASSERT. The original example was something along the lines of this:

void foo()
{
int x = 0;
C_ASSERT(x == 0);
x = 5;
C_ASSERT(x == 5);
}

This is *not* the intended use for C_ASSERT; you should use ASSERT here. This is not a matter of a “limitation” in C_ASSERT – it a matter of misusing C_ASSERT. C_ASSERT asserts that a condition is true at *compile* time – i.e. long before the code is actually run, and is true is all possible runs of the code. In this particular case, the compiler may be able to know value of “x” at this point, but that’s because the compiler is being clever. Consider this:

void foo()
{
int x = compute_x();
C_ASSERT(x == 0);
}

C_ASSERT is not the right choice here, since the value of compute_x() is only knowable at runtime, not compile time. There is no “going crazy with C_ASSERT” in C++, in the sense of replacing all uses of ASSERT with C_ASSERT. The only “going crazy” is not understanding the difference between compile-time and run-time.


From: xxxxx@lists.osr.com [xxxxx@lists.osr.com] On Behalf Of Pavel A. [xxxxx@writeme.com]
Sent: Saturday, January 06, 2007 4:13 AM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] C_ASSERT doesn’t work in C files

wrote in message news:xxxxx@ntdev…
>> you can’t have a naked { } block at global scope.
>
> Thanks for that, point taken. So you’re either a good C citizen and declare everything at beginning of scope, or use C++ and
> go crazy with C_ASSERTS :slight_smile:

Ok. Let it be two good catches :slight_smile:

–P


Questions? First check the Kernel Driver FAQ at http://www.osronline.com/article.cfm?id=256

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer

Hi Arlie,

No I am not missing the point. I’ve only thanked Alexandru for noticing this issue.
If C_ASSERT is used in the middle of a C function, the braces should be placed around it.
Of course, {} braces can’t be part of the macro itself, because this
will break use of C_ASSERT on the global scope,
but I agree with Alexandru that one may want to use the macro in the middle
of a function, not just in declaration part or global scope.

Regards,
–PA

For what reason would you put this in the middle of a function? I’ve heard
this claim before, but never heard an intelligent arguement on why you
would want it in the middle.


Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
http://www.windrvr.com
Remove StopSpam from the email to reply

wrote in message news:xxxxx@ntdev…
> Hi Arlie,
>
> No I am not missing the point. I’ve only thanked Alexandru for noticing
> this issue.
> If C_ASSERT is used in the middle of a C function, the braces should be
> placed around it.
> Of course, {} braces can’t be part of the macro itself, because this
> will break use of C_ASSERT on the global scope,
> but I agree with Alexandru that one may want to use the macro in the
> middle
> of a function, not just in declaration part or global scope.
>
> Regards,
> --PA
>
>
>

Indeed. Compilation asserts are useful for checking that data structure
constraint assumptions are not violated over time by negligent programmers,
uncontrolled source changes, or toolset upgrades. They are not runtime
asserts and generally do not belong inside functions.

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:bounce-274857-
xxxxx@lists.osr.com] On Behalf Of Don Burn
Sent: Sunday, January 07, 2007 9:16 AM
To: Windows System Software Devs Interest List
Subject: Re:[ntdev] C_ASSERT doesn’t work in C files

For what reason would you put this in the middle of a function? I’ve
heard
this claim before, but never heard an intelligent arguement on why you
would want it in the middle.


Don Burn (MVP, Windows DDK)
Windows 2k/XP/2k3 Filesystem and Driver Consulting
http://www.windrvr.com
Remove StopSpam from the email to reply

wrote in message news:xxxxx@ntdev…
> > Hi Arlie,
> >
> > No I am not missing the point. I’ve only thanked Alexandru for
> noticing
> > this issue.
> > If C_ASSERT is used in the middle of a C function, the braces should
> be
> > placed around it.
> > Of course, {} braces can’t be part of the macro itself, because this
> > will break use of C_ASSERT on the global scope,
> > but I agree with Alexandru that one may want to use the macro in the
> > middle
> > of a function, not just in declaration part or global scope.
> >
> > Regards,
> > --PA
> >
> >
> >
>
>
>
> —
> Questions? First check the Kernel Driver FAQ at
> http://www.osronline.com/article.cfm?id=256
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer

> I still think you’re missing the point (or someone is) about C_ASSERT vs ASSERT. The original example was something along the lines of this: void foo() { int x = 0; C_ASSERT(x == 0); x = 5; C_ASSERT(x == 5); }

Thank you for the explanation, again :slight_smile: It was a slip on my part, I certainly meant something along C_ASSERT(sizeof(x)==4);

For what reason would you put this in the middle of a function? I’ve heard this claim before, but never heard an intelligent arguement on why you would want it in the middle.

Indeed these static asserts belong either at the beginning of scope, or globally; however it might be convenient sometimes to plop one, say, right before allocating a chunk from a general-purpose lookaside list to make sure it’s big enough to fit some immediate purpose. (Much in the same way that it’s convenient to declare variables anywhere in C++.)

This is all for a minor readability convenience obviously; those static asserts I mentioned can be neatly grouped at the top and no-one’s the wiser.