max strlen at compile time?

G

Gernot Frisch

Hi,

can I use the preprocessor, using sizeof(a)/sizeof(a[0]) to yield an
error for too long strings?

Like:

#define CRYPT(a) \
#if sizeof(a)/sizeof(a[0]) > 31 \
xCRYPT(a) \
#else\
#error xy\
#endif

(which of course doe not work)


--
-Gernot
int main(int argc, char** argv) {printf
("%silto%c%cf%cgl%ssic%ccom%c", "ma", 58, 'g', 64, "ba", 46, 10);}

________________________________________
Looking for a good game? Do it yourself!
GLBasic - you can do
www.GLBasic.com
 
R

Richard Heathfield

Gernot Frisch said:
Hi,

can I use the preprocessor, using sizeof(a)/sizeof(a[0]) to yield an
error for too long strings?

No, the preprocessor doesn't resolve uses of sizeof - that's done by the
compiler later on.
 
R

Richard Tobin

can I use the preprocessor, using sizeof(a)/sizeof(a[0]) to yield an
error for too long strings?
[/QUOTE]
No, the preprocessor doesn't resolve uses of sizeof - that's done by the
compiler later on.

However, sizeof does produce a constant value, and there have been
tricks posted here in the past to detect errors of this kind at
compile time.

-- Richard
 
R

Richard Heathfield

Richard Tobin said:
can I use the preprocessor, using sizeof(a)/sizeof(a[0]) to yield an
error for too long strings?
No, the preprocessor doesn't resolve uses of sizeof - that's done by the
compiler later on.

However, sizeof does produce a constant value, and there have been
tricks posted here in the past to detect errors of this kind at
compile time.[/QUOTE]

Yes, but he specifically asked about the preprocessor. (Yeah, I know, the
subject line says "compile time"...)
 
G

Gernot Frisch

Richard Heathfield said:
Richard Tobin said:
Richard Heathfield said:
can I use the preprocessor, using sizeof(a)/sizeof(a[0]) to yield
an
error for too long strings?
No, the preprocessor doesn't resolve uses of sizeof - that's done
by the
compiler later on.

However, sizeof does produce a constant value, and there have been
tricks posted here in the past to detect errors of this kind at
compile time.

Yes, but he specifically asked about the preprocessor. (Yeah, I
know, the
subject line says "compile time"...)

Very nice. So - can somone please show me how to check for max
stringlength at _compile time_?
 
R

Richard Heathfield

Gernot Frisch said:
Yes, but he specifically asked about the preprocessor. [...]

Very nice. So - can somone please show me how to check for max
stringlength at _compile time_?

Oh, okay. Let's take your original example:

#define CRYPT(a) \
#if sizeof(a)/sizeof(a[0]) > 31 \
xCRYPT(a) \
#else\
#error xy\
#endif

Now let me just hack that to give a useful name that doesn't look silly when
quoted in ordinary text:

#define CRYPT(Array) \
#if sizeof(Array)/sizeof(Array[0]) > 31 \
xCRYPT(Array) \
#else\
#error xy\
#endif

What we want, then, is a compile-time error if the size of Array exceeds 31.
Here's how:

char Array[SUSPECT_LENGTH] = {0};
char Error_ArrayIsTooLong[((sizeof Array / sizeof Array[0] <= OKAY_LENGTH) *
2) - 1] = {0};

With OKAY_LENGTH set at 31 and SUSPECT_LENGTH at 31, I get:

gcc -W -Wall -ansi -pedantic -Wformat-nonliteral -Wcast-align
-Wpointer-arith -Wbad-function-cast -Wmissing-prototypes
-Wstrict-prototypes -Wmissing-declarations -Winline -Wundef
-Wnested-externs -Wcast-qual -Wshadow -Wconversion -Wwrite-strings
-Wno-conversion -ffloat-store -O2 -g -pg -c -o foo.o foo.c
foo.c: In function `main':
foo.c:9: warning: unused variable `Error_ArrayIsTooLong'

With OKAY_LENGTH set at 31 and SUSPECT_LENGTH at 32, I get:

gcc -W -Wall -ansi -pedantic -Wformat-nonliteral -Wcast-align
-Wpointer-arith -Wbad-function-cast -Wmissing-prototypes
-Wstrict-prototypes -Wmissing-declarations -Winline -Wundef
-Wnested-externs -Wcast-qual -Wshadow -Wconversion -Wwrite-strings
-Wno-conversion -ffloat-store -O2 -g -pg -c -o foo.o foo.c
foo.c: In function `main':
foo.c:9: size of array `Error_ArrayIsTooLong' is negative
foo.c:9: warning: unused variable `Error_ArrayIsTooLong'
make: *** [foo.o] Error 1

QED.
 
G

Gernot Frisch

What we want, then, is a compile-time error if the size of Array
exceeds 31.
Here's how:

char Array[SUSPECT_LENGTH] = {0};
char Error_ArrayIsTooLong[((sizeof Array / sizeof Array[0] <=
OKAY_LENGTH) *
2) - 1] = {0};
foo.c: In function `main':
foo.c:9: size of array `Error_ArrayIsTooLong' is negative
foo.c:9: warning: unused variable `Error_ArrayIsTooLong'


Very clever! Thank you.
 
H

Hallvard B Furuseth

Richard said:
What we want, then, is a compile-time error if the size of Array
exceeds 31. Here's how:

char Array[SUSPECT_LENGTH] = {0};
char Error_ArrayIsTooLong[((sizeof Array / sizeof Array[0] <= OKAY_LENGTH) *
2) - 1] = {0};

A lot of compilers are lax about error checking in one way or another -
I think I've seen one which converted that negative size to unsigned,
for example. So I prefer to violate two constraints, just in case:

#define CHECK_CONSTRAINT(name, test) \
typedef struct { \
int constraint_##name: (test) ? 1 : -999; \
} constraint_##name[(test) ? 1 : -999]

CHECK_CONSTRAINT(Array_size, sizeof Array/sizeof Array[0] <= OKAY_LENGTH)
 
G

Gernot Frisch

Hallvard B Furuseth said:
Richard said:
What we want, then, is a compile-time error if the size of Array
exceeds 31. Here's how:

char Array[SUSPECT_LENGTH] = {0};
char Error_ArrayIsTooLong[((sizeof Array / sizeof Array[0] <=
OKAY_LENGTH) *
2) - 1] = {0};

A lot of compilers are lax about error checking in one way or
another -
I think I've seen one which converted that negative size to
unsigned,
for example. So I prefer to violate two constraints, just in case:

#define CHECK_CONSTRAINT(name, test) \
typedef struct { \
int constraint_##name: (test) ? 1 : -999; \
} constraint_##name[(test) ? 1 : -999]

CHECK_CONSTRAINT(Array_size, sizeof Array/sizeof Array[0] <=
OKAY_LENGTH)

how about this:

{
const char err_str_too_long[
(sizeof(str)/sizeof(str[0]) <= 32)+1
] ={0,0};
}

which makes an [1] or a [2], and yields an error:
error C2078: too many initializers

which is quite informative, I think...

Is it x-compiler compatible?
 
H

Hallvard B Furuseth

Gernot said:
(...)

how about this:

{
const char err_str_too_long[
(sizeof(str)/sizeof(str[0]) <= 32)+1
] ={0,0};
}

which makes an [1] or a [2], and yields an error:
error C2078: too many initializers

which is quite informative, I think...

Heh. Quite fitting for that particular error. gcc only gives a warning
about it though. Compilation only fails if you use gcc -pedantic-errors.
Hmm. I'll suggest to change that and see what they say. It's not a bug
do behave like that, just unexpected.

One matter I didn't notice at first is that your and Richard's variants
generate data, while mine doesn't (it just makes a typedef).
 
L

Laurent Deniau

Gernot said:
What we want, then, is a compile-time error if the size of Array
exceeds 31.
Here's how:

char Array[SUSPECT_LENGTH] = {0};
char Error_ArrayIsTooLong[((sizeof Array / sizeof Array[0] <=
OKAY_LENGTH) *
2) - 1] = {0};

foo.c: In function `main':
foo.c:9: size of array `Error_ArrayIsTooLong' is negative
foo.c:9: warning: unused variable `Error_ArrayIsTooLong'



Very clever! Thank you.

Your problem can be generalized to "how to program an elegant and robust
static assert" (compile time assert). Here is what I use (open to any
improvement):

#define cos_STATIC_ASSERT(cond) \
struct cos_PP_CAT(STATIC_ASSERT_,__LINE__) { \
enum { cos_PP_CAT(STATIC_ASSERT_,__LINE__) = !(cond) } _; \
int STATIC_ASSERT[(cond) ? 1 : -1]; \
}

where

#define cos_PP_CAT( a,b) cos_PP_CAT_(a,b)
#define cos_PP_CAT_(a,b) a##b

This should give a meaningfull error message with most compilers.
The enum is there to forbid the use of sizeof at runtime (c99) and to
ensure consistent behavior between c89 and c99.

a+, ld.
 
G

Gernot Frisch

One matter I didn't notice at first is that your and Richard's
variants
generate data, while mine doesn't (it just makes a typedef).

That's a point!
 
F

Frederick Gotham

Laurent Deniau posted:
int STATIC_ASSERT[(cond) ? 1 : -1];


Would you not prefer a simple typedef?

(COMPASS = Compile-time assert)

Something like:

typedef COMPASS(expr) char[(expr) ? 2 : -2 ];
 
B

Ben Pfaff

Frederick Gotham said:
Laurent Deniau posted:
int STATIC_ASSERT[(cond) ? 1 : -1];


Would you not prefer a simple typedef?

(COMPASS = Compile-time assert)

Something like:

typedef COMPASS(expr) char[(expr) ? 2 : -2 ];

verify.h from gnulib is a refined version of the idea of a
compile-time assert. I won't post it here, because it's about
150 lines long (mostly comments), but I'd recommend taking a look
at on the web:
http://cvs.savannah.gnu.org/viewcvs.../verify.h?content-type=text/plain&root=gnulib

I found it very educational.
 
L

Laurent Deniau

Frederick said:
Laurent Deniau posted:

int STATIC_ASSERT[(cond) ? 1 : -1];



Would you not prefer a simple typedef?
why?

(COMPASS = Compile-time assert)

Something like:

typedef COMPASS(expr) char[(expr) ? 2 : -2 ];

This may not detect some problems at compile time but at runtime in c99.

a+, ld.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,781
Messages
2,569,615
Members
45,297
Latest member
EngineerD

Latest Threads

Top