473,385 Members | 1,753 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

Is it possible to make void * safer?

I was just thinking about the virtues of C vs. C++ wrt. ADT/generic
programming. The biggest complaint about writing container libraries for
ADTs is that void * offers no type safety. Does it really have to be this
way?

Couldn't you for instance track an object's accesses with void pointers and
ensure they are used consistently across calls?

---------

typedef struct {
size_t count;
/* ... */
void *data;
} array_t;

int array_push(array_t *array, void *data);
void *array_pop(array_t *array);

---------

Based on these two interface functions, we can on an individual object of
type array_t track that the parameter passed to push() has the same type as
the one to which you would assign from the pop() function.

Of course, for functions that take multiple void arguments or use void
arguments in inconsistent ways, we would need to track how those arguments
are used and are eventually assigned/read to/from the members of type
array_t.

This would appear to work in theory for code in which you have all the
source files available. It falls apart however when you only have a header
file as a specification for a pre-compiled library. I suppose since the
parameter identifiers are optional in function prototypes that you might be
able to divine something if the programmer elects to use some sort of
predictable naming for the void arguments.

At any rate, it was just a random thought. My idea is full of holes but it
was at least in the spirit of C :)

Thanks,

-Clint
Feb 22 '06 #1
19 1622
Clint Olsen <cl***@0lsen.net> wrote:
# I was just thinking about the virtues of C vs. C++ wrt. ADT/generic
# programming. The biggest complaint about writing container libraries for
# ADTs is that void * offers no type safety. Does it really have to be this
# way?

Then don't use C. There are other languages that are plenty
type safe. You can even write your front end to convert
a more sophisticated type checking language into C, or hire
people like me to write a front end for you.

--
SM Ryan http://www.rawbw.com/~wyrmwif/
JUSTICE!
Justice is dead.
Feb 22 '06 #2
Clint Olsen wrote:
I was just thinking about the virtues of C vs. C++ wrt. ADT/generic
programming. The biggest complaint about writing container libraries for
ADTs is that void * offers no type safety. Does it really have to be this
way?
Its not just void *, but <anything> * that has little to no type
safety. That's C's *real* problem w.r.t. safety. If you want to avoid
void *, its not a problem, but avoiding pointers in general -- you
won't get too far in C trying that.
Couldn't you for instance track an object's accesses with void pointers and
ensure they are used consistently across calls?

---------

typedef struct {
size_t count;
/* ... */
void *data;
} array_t;

int array_push(array_t *array, void *data);
void *array_pop(array_t *array);

---------


Well actually the way to do this is as follows:

struct tagarray {
size_t count;
/* ... */
void * data;
};

extern int untyped_array_push (struct tagarray *array, void *data);
extern void *untyped_array_pop (struct tagarray *array);

Then you write the following wrappers:

struct <name>_tagarrwrap {
struct tagarray generic;
}

int <name>_array_push (struct <name>_tagarrwrap *array, <type> * data)
{
return untyped_array_push (&array->generic, (void *) data);
}

<type> * <name>_array_pop (struct <name>_tagarrwrap *array) {
return (<type> *) untyped_array_pop (&array->generic);
}

The point is that these wrappers are so syntactically trivial, that you
can invoke them as a result of some (name, type) indexed macro. Then
you just use these wrapper functions.

Now if C were any good of a language, this would be *perfect*. You
could even hide the struct tagarray definition inside a generic module
(its definition is unnecessary except for the generic void * function
implementations), this would be about as safe as you get -- *EXCEPT* C
is so worthless ...

No matter what <type> you pick, you won't get any type safety. For
example, if we've set up an int array:

genericArrayImpl (foo, int); /* Let's say this is our macro */
struct foo_tagarrwrap arrInt;
float y = 2.0; /* This is not an int */

foo_array_push (arrInt, &y);

The compiler won't even give you a warning here. You don't actually
*have* anything resembling typesafety in C. You need to use a C++
compiler before you are informed of any kind of an error here.

So we've avoided void*, but we haven't actually gained any typesafety,
unless we require the use of a C++ compiler. But in that case, why not
simply use the C++ language capabilities to do this right via
templates?

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Feb 22 '06 #3
<snip>
genericArrayImpl (foo, int); /* Let's say this is our macro */
struct foo_tagarrwrap arrInt;
float y = 2.0; /* This is not an int */

foo_array_push (arrInt, &y);

The compiler won't even give you a warning here. You don't actually
*have* anything resembling typesafety in C. You need to use a C++
compiler before you are informed of any kind of an error here.


Huh? It is illegal to implicitly convert from float* to int*, if that's what
you are hinting at. See sections 6.5.16.1 of the C99 spec, for example. The
OP posted that void* is the gateway to implicitly throwing away type safety
and he's right.
Feb 22 '06 #4
On 2006-02-22, we******@gmail.com <we******@gmail.com> wrote:
So we've avoided void*, but we haven't actually gained any typesafety,
unless we require the use of a C++ compiler. But in that case, why not
simply use the C++ language capabilities to do this right via templates?


Thanks for your post.

The problem I have with C++ and other template-style programming is that
the functions are instantiated for every unique type they use. It sort of
reminds me of the old days of C++ that where it was primarily a language
front-end and just blurted out C. Yeah, it's type safe, but it seems like
we could make smarter compilers that used the _same_ exact code to do the
same work. I don't know enough about generic programming support in other
languages to compare C++ against, but it seems they are sort of doing an
end-around approach to get type safety. After all, it's just damn bytes
we're talking about in the end.

Thanks,

-Clint
Feb 22 '06 #5
On 22 Feb 2006 09:55:15 -0800, in comp.lang.c , we******@gmail.com
wrote:
Clint Olsen wrote:
I was just thinking about the virtues of C vs. C++ wrt. ADT/generic
programming. The biggest complaint about writing container libraries for
ADTs is that void * offers no type safety. Does it really have to be this
way?
Its not just void *, but <anything> * that has little to no type
safety. That's C's *real* problem w.r.t. safety.


Well sure, C isn't particularly type safe. Since when is this news? If
you want C++ you know where to find it.
Now if C were any good of a language,
Here we go again.
No matter what <type> you pick, you won't get any type safety. For
example, if we've set up an int array:

genericArrayImpl (foo, int); /* Let's say this is our macro */
struct foo_tagarrwrap arrInt;
float y = 2.0; /* This is not an int */

foo_array_push (arrInt, &y);

The compiler won't even give you a warning here.


If you've avoided void*, then the compiler will warn you about the
above, since int* and float* are incompatible, as are float* and a
pointer-to-struct.

You don't actually know C that well do you?
Mark McIntyre
--
"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan

----== Posted via Newsfeeds.Com - Unlimited-Unrestricted-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption =----
Feb 22 '06 #6

"Clint Olsen" <cl***@0lsen.net> wrote in message
news:sl******************@belle.0lsen.net...
I was just thinking about the virtues of C vs. C++ wrt. ADT/generic
programming. The biggest complaint about writing container libraries for
ADTs is that void * offers no type safety. Does it really have to be this
way?

Couldn't you for instance track an object's accesses with void pointers and ensure they are used consistently across calls?


From the other posts, it sounds like you may need C to be completely safe.
There are a number of programs which will help you make your C programs much
safer, such as LINT, CCURED, or CIL. Or, you could switch to a different
language such as Lustre and then run SCADE which was used sucessfully with
EADS Airbus.

Rod Pemberton


Feb 23 '06 #7
Clint Olsen wrote:
On 2006-02-22, we******@gmail.com <we******@gmail.com> wrote:
So we've avoided void*, but we haven't actually gained any typesafety,
unless we require the use of a C++ compiler. But in that case, why not
simply use the C++ language capabilities to do this right via templates?

Thanks for your post.

The problem I have with C++ and other template-style programming is that
the functions are instantiated for every unique type they use. It sort of
reminds me of the old days of C++ that where it was primarily a language
front-end and just blurted out C. Yeah, it's type safe, but it seems like
we could make smarter compilers that used the _same_ exact code to do the
same work.


Well you can do this with a container like you describe by using void*
for the internals, with a template wrapper that imposes the type safety.
With care, the wrapper member functions are trivial and will be
inlined away.

You probably could simulate this is C with a struct comprising function
pointers defined within a macros, something like:

#define X( type ) \
typedef struct xX##type { \
void (*push)( array_t*, type ); \
} X##type; \
void push##type##( array_t* array, type data ) { \
array_push( array, (void*)data); }

#define GET_X( type, name ) \
X##type name; \
name.push = push##type;

X(int)

int main()
{
GET_X( int, x );
array_t array;
x.push( &array, 42 );
}

--
Ian Collins.
Feb 23 '06 #8
Ian Collins wrote:
Clint Olsen wrote:
On 2006-02-22, we******@gmail.com <we******@gmail.com> wrote:
So we've avoided void*, but we haven't actually gained any typesafety,
unless we require the use of a C++ compiler. But in that case, why not
simply use the C++ language capabilities to do this right via templates?

Thanks for your post.

The problem I have with C++ and other template-style programming is that
the functions are instantiated for every unique type they use. It sort of
reminds me of the old days of C++ that where it was primarily a language
front-end and just blurted out C. Yeah, it's type safe, but it seems like
we could make smarter compilers that used the _same_ exact code to do the
same work.


Well you can do this with a container like you describe by using void*
for the internals, with a template wrapper that imposes the type safety.
With care, the wrapper member functions are trivial and will be
inlined away.

You probably could simulate this is C with a struct comprising function
pointers defined within a macros, something like:

#define X( type ) \
typedef struct xX##type { \
void (*push)( array_t*, type ); \
} X##type; \
void push##type##( array_t* array, type data ) { \
array_push( array, (void*)data); }


Well this means that the data is getting implicitely copied into from
the call site to the local parameter. The cast to (void *) looks
wrong, I think you mean: (void *)&data, but you're still getting 1
shallow copy (suppose <type> is a struct.)
#define GET_X( type, name ) \
X##type name; \
name.push = push##type;


I'm not sure what you're gaining from this function pointer abstraction
since you are requiring, specifically "push##type" to exist in file
scope.

I think my way works best in practice, *except* for the fact that when
you build many of them for various types, the lack of type safety so
easily leads to utter chaos. Unless you run it through a C++ compiler,
but then its just ironic.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Feb 23 '06 #9
we******@gmail.com wrote:

You probably could simulate this is C with a struct comprising function
pointers defined within a macros, something like:

#define X( type ) \
typedef struct xX##type { \
void (*push)( array_t*, type ); \
} X##type; \
void push##type##( array_t* array, type data ) { \
array_push( array, (void*)data); }

Well this means that the data is getting implicitely copied into from
the call site to the local parameter. The cast to (void *) looks
wrong, I think you mean: (void *)&data, but you're still getting 1
shallow copy (suppose <type> is a struct.)

Actually, it should have been 'type* data )' in the function definition,
I was assuming type was a struct.
#define GET_X( type, name ) \
X##type name; \
name.push = push##type;

I'm not sure what you're gaining from this function pointer abstraction
since you are requiring, specifically "push##type" to exist in file
scope.

The ability to create an instance of the object, as illustrated by the
example push in my original post.

I was specifically demonstrating how to mimic template in C with macros.
I think my way works best in practice, *except* for the fact that when
you build many of them for various types, the lack of type safety so
easily leads to utter chaos. Unless you run it through a C++ compiler,
but then its just ironic.

That's why I added the function pointers, they are type safe.

--
Ian Collins.
Feb 23 '06 #10
Ian Collins wrote:
we******@gmail.com wrote:
You probably could simulate this is C with a struct comprising function
pointers defined within a macros, something like:

#define X( type ) \
typedef struct xX##type { \
void (*push)( array_t*, type ); \
} X##type; \
void push##type##( array_t* array, type data ) { \
array_push( array, (void*)data); }
Well this means that the data is getting implicitely copied into from
the call site to the local parameter. The cast to (void *) looks
wrong, I think you mean: (void *)&data, but you're still getting 1
shallow copy (suppose <type> is a struct.)


Actually, it should have been 'type* data )' in the function definition,
I was assuming type was a struct.


Well, then x.push (array, <any pointer>) is not going to be properly
type checked.
#define GET_X( type, name ) \
X##type name; \
name.push = push##type;

I'm not sure what you're gaining from this function pointer abstraction
since you are requiring, specifically "push##type" to exist in file
scope.


The ability to create an instance of the object, as illustrated by the
example push in my original post.

I was specifically demonstrating how to mimic template in C with macros.


Well, you are also using function pointers. This is a performance
concession, especially if you allow it to have an external interface --
then the compiler can't be "smart", and you eat the indirect function
call cost.
I think my way works best in practice, *except* for the fact that when
you build many of them for various types, the lack of type safety so
easily leads to utter chaos. Unless you run it through a C++ compiler,
but then its just ironic.


That's why I added the function pointers, they are type safe.


Uhhm ... not on the C compilers I use. In fact, I encourage a related
function pointer abuse in Bstrlib (though, I don't require it -- you
can be to the letter if you want; and they are cases where no real
system is actually going to go wrong) for some cases, and it doesn't
come up as an issue.
From what I can tell, pointers are basically never checked by the

compilers -- they take the attitude that all pointers are the same (or
that the programmer knows what s/he's doing), and this includes
function pointer parameters. You have to actually dereference before
you get an error. Obviously you can't get away with this in C++.

I'll check this all again when I get access to a compiler again (I am
not near that kind of a system right now) but I'm pretty sure
contemporary modern C compilers all just screw you on this issue. (The
question is -- is this a "NULLStone" compliance issue, or what? -- Why
do *ALL* the C compilers screw you on this?)

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Feb 23 '06 #11
we******@gmail.com wrote:

I'm not sure what you're gaining from this function pointer abstraction
since you are requiring, specifically "push##type" to exist in file
scope.
The ability to create an instance of the object, as illustrated by the
example push in my original post.

I was specifically demonstrating how to mimic template in C with macros.

Well, you are also using function pointers. This is a performance
concession, especially if you allow it to have an external interface --
then the compiler can't be "smart", and you eat the indirect function
call cost.

Agreed, that's one big hit when simulating templates over using C++
templates. C++ compiles will inline the trivial wrapper functions.
I think my way works best in practice, *except* for the fact that when
you build many of them for various types, the lack of type safety so
easily leads to utter chaos. Unless you run it through a C++ compiler,
but then its just ironic.


That's why I added the function pointers, they are type safe.

Uhhm ... not on the C compilers I use. In fact, I encourage a related
function pointer abuse in Bstrlib (though, I don't require it -- you
can be to the letter if you want; and they are cases where no real
system is actually going to go wrong) for some cases, and it doesn't
come up as an issue.

Yes it will complain, based on my earlier macros:

#define X( type ) \
typedef struct xX##type { \
void (*push)( array_t*, type ); \
} X##type; \
\
void push##type##( array_t* array, type data ) { \
array_push( array, data); }

#define GET_X( type, name ) \
X##type name; \
name.push = push##type;

typedef int* intp;

X(intp)

int main()
{
GET_X( intp, x );

array_t array;
int n = 0;
float f = 0.0;
x.push( &array, &n );
x.push( &array, &f );
}

Will generate warnings for x.push( &array, &f );

--
Ian Collins.
Feb 23 '06 #12
we******@gmail.com writes:
[...]
From what I can tell, pointers are basically never checked by the
compilers -- they take the attitude that all pointers are the same (or
that the programmer knows what s/he's doing), and this includes
function pointer parameters. You have to actually dereference before
you get an error. Obviously you can't get away with this in C++.

I'll check this all again when I get access to a compiler again (I am
not near that kind of a system right now) but I'm pretty sure
contemporary modern C compilers all just screw you on this issue. (The
question is -- is this a "NULLStone" compliance issue, or what? -- Why
do *ALL* the C compilers screw you on this?)


void foo(void)
{
int *ip;
float *fp;
ip = fp;
fp = ip;
}
% gcc -c tmp.c
tmp.c: In function `foo':
tmp.c:5: warning: assignment from incompatible pointer type
tmp.c:6: warning: assignment from incompatible pointer type

Show us an example that you think *ALL* C compilers screw you on.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Feb 23 '06 #13
Ian Collins wrote:
we******@gmail.com wrote:
I think my way works best in practice, *except* for the fact that when
you build many of them for various types, the lack of type safety so
easily leads to utter chaos. Unless you run it through a C++ compiler,
but then its just ironic.

That's why I added the function pointers, they are type safe.


Uhhm ... not on the C compilers I use. In fact, I encourage a related
function pointer abuse in Bstrlib (though, I don't require it -- you
can be to the letter if you want; and they are cases where no real
system is actually going to go wrong) for some cases, and it doesn't
come up as an issue.


Yes it will complain, based on my earlier macros:

#define X( type ) \
typedef struct xX##type { \
void (*push)( array_t*, type ); \
} X##type; \
\
void push##type##( array_t* array, type data ) { \
array_push( array, data); }

#define GET_X( type, name ) \
X##type name; \
name.push = push##type;

typedef int* intp;

X(intp)

int main() {
GET_X( intp, x );

array_t array;
int n = 0;
float f = 0.0;
x.push( &array, &n );
x.push( &array, &f );
}

Will generate warnings for x.push( &array, &f );


Have you tried it? After adding in a return 0; MSVC 6.0 says there are
no problems at its highest warning level. I'll check it with Intel,
Watcom, Borland, and gcc in a couple days, but my recollection is that
only Intel at its very highest warning level says anything -- but
Intel's highest warning level is annoying (it tells you strlen(s) +
strlen(t) is suspect because strlen could be overridden and have a side
effect and the + operation does not guarantee order) and I think a lot
of people dial it down at least one level from the highest, at which
point we lose this warning.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Feb 23 '06 #14
we******@gmail.com writes:
Ian Collins wrote:

[...]
Yes it will complain, based on my earlier macros:

#define X( type ) \
typedef struct xX##type { \
void (*push)( array_t*, type ); \
} X##type; \
\
void push##type##( array_t* array, type data ) { \
array_push( array, data); }

#define GET_X( type, name ) \
X##type name; \
name.push = push##type;

typedef int* intp;

X(intp)

int main() {
GET_X( intp, x );

array_t array;
int n = 0;
float f = 0.0;
x.push( &array, &n );
x.push( &array, &f );
}

Will generate warnings for x.push( &array, &f );


Have you tried it? After adding in a return 0; MSVC 6.0 says there are
no problems at its highest warning level. I'll check it with Intel,
Watcom, Borland, and gcc in a couple days, but my recollection is that
only Intel at its very highest warning level says anything -- but
Intel's highest warning level is annoying (it tells you strlen(s) +
strlen(t) is suspect because strlen could be overridden and have a side
effect and the + operation does not guarantee order) and I think a lot
of people dial it down at least one level from the highest, at which
point we lose this warning.


I'm surprised you got far enough to get any warnings. When I compiled
the above code with gcc, I got:

tmp.c:15: error: parse error before '*' token
tmp.c:15:1: pasting "pushintp" and "(" does not give a valid preprocessing token
tmp.c:15: error: parse error before '*' token

followed by a cascade of other errors.

Getting rid of the macros and stripping down the program, I tried
this:

void push_int(int *ptr)
{
/* ... */
}

int main(void)
{
struct {
void (*push)(int*);
} x;
x.push = push_int;
int n = 0;
float f = 0.0;
x.push( &n );
x.push( &f ); /* This is line 15 */
return 0;
}

"gcc -c tmp.c" gave me:

tmp.c: In function `main':
tmp.c:15: warning: passing arg 1 of pointer to function from incompatible pointer type

(This was without any arguments to increase the warning level.)

If you're using a compiler that doesn't at least warn you about this
kind of type mismatch, get a better compiler.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Feb 24 '06 #15
we******@gmail.com wrote:

Will generate warnings for x.push( &array, &f );

Have you tried it? After adding in a return 0; MSVC 6.0 says there are
no problems at its highest warning level.


Well it should. That's a rather old and non-compliant compiler.

Sun cc (normal warnings) gives:

"/tmp/x.c", line 28: warning: argument #2 is incompatible with prototype:
prototype: pointer to int : "unknown", line 0
argument : pointer to float

gcc (normal warnings) gives:

/tmp/x.c: In function `main':
/tmp/x.c:28: warning: passing arg 2 of pointer to function from
incompatible pointer type

--
Ian Collins.
Feb 24 '06 #16
Keith Thompson wrote:


I'm surprised you got far enough to get any warnings. When I compiled
the above code with gcc, I got:

tmp.c:15: error: parse error before '*' token
tmp.c:15:1: pasting "pushintp" and "(" does not give a valid preprocessing token
tmp.c:15: error: parse error before '*' token

Interesting, gcc4 gives the error, gcc3 does not.

Which is correct and if it's gcc4, how does one use the preprocessor to
build a function prototype?

--
Ian Collins.
Feb 24 '06 #17
Ian Collins <ia******@hotmail.com> writes:
Keith Thompson wrote:
I'm surprised you got far enough to get any warnings. When I
compiled
the above code with gcc, I got:
tmp.c:15: error: parse error before '*' token
tmp.c:15:1: pasting "pushintp" and "(" does not give a valid preprocessing token
tmp.c:15: error: parse error before '*' token

Interesting, gcc4 gives the error, gcc3 does not.

Which is correct and if it's gcc4, how does one use the preprocessor
to build a function prototype?


The first thing I'd do is drop the unnecessary ## operator that tried
to join an identifier to a '('. When I tried that with the posted
program, I got other errors that I didn't bother to track down.

To summarize: I don't know.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Feb 24 '06 #18
Keith Thompson wrote:
Ian Collins <ia******@hotmail.com> writes:
Keith Thompson wrote:
I'm surprised you got far enough to get any warnings. When I
compiled
the above code with gcc, I got:
tmp.c:15: error: parse error before '*' token
tmp.c:15:1: pasting "pushintp" and "(" does not give a valid preprocessing token
tmp.c:15: error: parse error before '*' token


Interesting, gcc4 gives the error, gcc3 does not.

Which is correct and if it's gcc4, how does one use the preprocessor
to build a function prototype?

The first thing I'd do is drop the unnecessary ## operator that tried
to join an identifier to a '('. When I tried that with the posted
program, I got other errors that I didn't bother to track down.

You're right, removing the unnecessary ## fixes the error. It was
redundant anyway.

Adding

typedef int array_t;
extern int array_push(array_t *array, void *data);

to the top of the file as a kludge will remove any remaining errors.

--
Ian Collins.
Feb 24 '06 #19
Ian Collins wrote:
Keith Thompson wrote:
Ian Collins <ia******@hotmail.com> writes:
Keith Thompson wrote:
I'm surprised you got far enough to get any warnings. When I
compiled
the above code with gcc, I got:
tmp.c:15: error: parse error before '*' token
tmp.c:15:1: pasting "pushintp" and "(" does not give a valid preprocessing token
tmp.c:15: error: parse error before '*' token

Interesting, gcc4 gives the error, gcc3 does not.

Which is correct and if it's gcc4, how does one use the preprocessor
to build a function prototype?

The first thing I'd do is drop the unnecessary ## operator that tried
to join an identifier to a '('. When I tried that with the posted
program, I got other errors that I didn't bother to track down.


You're right, removing the unnecessary ## fixes the error. It was
redundant anyway.

Adding

typedef int array_t;
extern int array_push(array_t *array, void *data);

to the top of the file as a kludge will remove any remaining errors.


I have implemented the whole shehbang here:

http://www.pobox.com/~qed/gstack.zip

The ## rules are annoying, and I find that in general, the way to deal
with them is to wrap that whole thing in a two-level macro itself (it
works, so long as we don't care about namespace invasion).

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Feb 27 '06 #20

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

22
by: Robert Brown | last post by:
suppose I have the following table: CREATE TABLE (int level, color varchar, length int, width int, height int) It has the following rows 1, "RED", 8, 10, 12 2, NULL, NULL, NULL, 20...
5
by: johny smith | last post by:
I have never really understood the purpose of the void*. I guess it is so different data types could for instance be passed into a function. And then the function will re cast it to the correct...
4
by: john smith | last post by:
I have never really understood the difference between the two notations below. I often run into code where they are passing in the address of some location. Some people do something like...
48
by: yezi | last post by:
Hi, all: I want to record some memory pointer returned from malloc, is possible the code like below? int memo_index; int i,j; char *tmp; for (i=0;i<10;i++){
4
by: robinsand | last post by:
Header File: car.h #if !defined CAR_H #define CAR_H enum TCarType { ctEconomy = 1, ctCompact, ctStandard, ctFullSize, ctMiniVan, ctSUV }; class Car { public: Car();
41
by: SRR | last post by:
Why is it discouraged to explicitly typecast the void pointer returned by malloc(); function? For example: { int *p; p = (int*)malloc(2*sizeof(int)); /*Explicit casting is done, therfore it...
9
by: jason.cipriani | last post by:
All right, I'm in this weird situation that's hard to explain but I've put together a small example program that represents it. Please bear with the fact that some of the stuff in the example seems...
11
by: Litvinov Sergey | last post by:
My problem is the following one. I have a huge number of objects of base class: class Base { public: virtual void method(); } And a derived class:
160
by: raphfrk | last post by:
Is this valid? int a; void *b; b = (void *)a; // b points to a b += 5*sizeof(*a); // b points to a a = 100;
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.