C Types and void *'s

Programming, for all ages and all languages.
Post Reply
User avatar
Alboin
Member
Member
Posts: 1466
Joined: Thu Jan 04, 2007 3:29 pm
Location: Noricum and Pannonia

C Types and void *'s

Post by Alboin »

A somewhat quick question:

A void * has no type. So, if I have two functions that do the same thing, but with an 8 bit character, and an 16 bit short, couldn't I just combine the two and do something like:

Code: Select all

void tada(void *data, int bits)
And then just cast to the correct type when it would be needed according to bits? Like:

Code: Select all

*((char *)data)
Would this cause any difficulties? I just want to make sure before convert several hundred lines of code to a system like this.

Thanks.
C8H10N4O2 | #446691 | Trust the nodes.
earlz
Member
Member
Posts: 1546
Joined: Thu Jul 07, 2005 11:00 pm
Contact:

Post by earlz »

yea, though in most cases, you can use the largest used type and then just cast your small char to the short(or int)
course, this won't work in some cases though...

but yea, that is how I did some code for some project(might've been Open86) it was a little bit annoying though..
User avatar
Alboin
Member
Member
Posts: 1466
Joined: Thu Jan 04, 2007 3:29 pm
Location: Noricum and Pannonia

Post by Alboin »

hckr83 wrote:might've been Open86
That's actually what I'm working on. :) I'm kind of reorganizing some things...

Converting to the larger type seems even simpler. What problems are there?
C8H10N4O2 | #446691 | Trust the nodes.
earlz
Member
Member
Posts: 1546
Joined: Thu Jul 07, 2005 11:00 pm
Contact:

Post by earlz »

none _usually_ but for umm...well, it just keeps the function from knowing how many actual bits were sent..
like for the ports thing, if you just use a larger type, then some ports act differently depending on whether they get a byte or word, and that could keep the port from knowing which thing to use..
User avatar
Alboin
Member
Member
Posts: 1466
Joined: Thu Jan 04, 2007 3:29 pm
Location: Noricum and Pannonia

Post by Alboin »

Oh....Well that's why I have the 'int bits' argument.

All is well,
Thanks!
C8H10N4O2 | #446691 | Trust the nodes.
earlz
Member
Member
Posts: 1546
Joined: Thu Jul 07, 2005 11:00 pm
Contact:

Post by earlz »

wow! you've been busy...lol 5 more commits..(I think today only) anyway..
User avatar
Alboin
Member
Member
Posts: 1466
Joined: Thu Jan 04, 2007 3:29 pm
Location: Noricum and Pannonia

Post by Alboin »

hckr83 wrote:wow! you've been busy...lol 5 more commits..(I think today only) anyway..
Ahem...I would rather not talk about some of those commits. :D

SVN was acting up on me...Eventually I got it, but nonetheless...

I basically just rearranged some things. Switched the build system from GNU build tools to Scon, etc. I haven't committed my current SConstruct file. It's completely cross platform. (At least, as far as I know.)

That's about it. Now I'm organizing the code and making it a bit more clean, before I actually do anything major.
C8H10N4O2 | #446691 | Trust the nodes.
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Post by Colonel Kernel »

Doing what you describe is generally considered to be a Bad Idea. The more the compiler can help you by type-checking, the fewer bugs you'll have to find yourself, the hard way.

That said, it isn't really easy to write polymorphic functions in C, so I can sympathize. However, there are ways around it.

If your function always takes some kind of integer, one thing you can do is type the argument as uintptr_t (defined in C99... you might have to include stdint.h, or write your own -- I forget). It is the same size as a pointer on any architecture (e.g. -- it is 32-bits on x86 and 64-bits on x64). If you need signed integers, use intptr_t. If you don't want to cast all the time when calling the function, you can write a bunch of "front-ends" to it that each take the appropriate type and do the cast for you (this is what I do in my kernel).

You could also use macros, but you could also always gouge out your eyes with a butter knife. I'm not sure why you'd want to.

You could switch to C++ and use templates -- that's what they were invented for.

If your function is supposed to take a lot of different types that are a lot different from each other, you could always use a "discriminated union" -- that's a struct with two fields -- a union, and a type indicator that tells you what field of the union is valid.

There is actually a C API in common use today that does what you describe -- ODBC. Those of us who live and breathe it every day wish that it didn't abuse void* the way it does. :P
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
User avatar
Alboin
Member
Member
Posts: 1466
Joined: Thu Jan 04, 2007 3:29 pm
Location: Noricum and Pannonia

Post by Alboin »

Okay. I just went with a few void *'s, which I then quickly abstracted. Thanks.

Somewhat related is this:

Code: Select all

typedef struct {
	unsigned char high;
	unsigned char low;
}bits8;

typedef union {
	unsigned short bit16;
	bits8 bit8;
}reg;
This emulates the 16 bit registers of x86. I was pretty excited about it. It's so elegant and peaceful. Just another solution instead of using pointers everywhere. :)

Toodles.
C8H10N4O2 | #446691 | Trust the nodes.
earlz
Member
Member
Posts: 1546
Joined: Thu Jul 07, 2005 11:00 pm
Contact:

Post by earlz »

lol..good luck changing all of those *gregs8[AL] to that....lol..find and replace is your friend!
User avatar
Alboin
Member
Member
Posts: 1466
Joined: Thu Jan 04, 2007 3:29 pm
Location: Noricum and Pannonia

Post by Alboin »

Just had another idea for the void * issue.

You could use stdarg and just create a function something like:

Code: Select all

int add(int bits, ...)
Then, if bits is 8 you get 2 chars, and if it's 16 you get 2 shorts.

You know, there's a lot of ways to go about things in C...

Who needs templates? :)
C8H10N4O2 | #446691 | Trust the nodes.
User avatar
B.E
Member
Member
Posts: 275
Joined: Sat Oct 21, 2006 5:29 pm
Location: Brisbane Australia
Contact:

Post by B.E »

Alboin wrote:Just had another idea for the void * issue.

You could use stdarg and just create a function something like:

Code: Select all

int add(int bits, ...)
Then, if bits is 8 you get 2 chars, and if it's 16 you get 2 shorts.

You know, there's a lot of ways to go about things in C...

Who needs templates? :)
C will convert small types to bigger types for you (don't exacly know what you are tring to do thorugh). Also C will sign extend the type for you too.

so you would do something like this if signed:

Code: Select all

short add_signed(short a, short b){
   return a+b;
}
the unsigned version would look like this:

Code: Select all

unsigned short add_unsigned(unsigned short a, unsigned short b){
   return a+b;
}

and to use it in your code you would do the following

Code: Select all

char a,b;
char c;

short d;
short e,f;

a=b=3;
e=f=3;

// Add two bytes
c = (char)add(a,b);
// Add two 16-bit integers
d = add(e,f);
EDIT: This whole function code be a #define, i.e

Code: Select all

#define add(a,b) (a + b)
Image
Microsoft: "let everyone run after us. We'll just INNOV~1"
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Post by Colonel Kernel »

Alboin wrote:Who needs templates? :)
People who appreciate the benefits of type safety. :twisted:
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Post by Candy »

Alboin wrote:Just had another idea for the void * issue.

You could use stdarg and just create a function something like:

Code: Select all

int add(int bits, ...)
Then, if bits is 8 you get 2 chars, and if it's 16 you get 2 shorts.

You know, there's a lot of ways to go about things in C...

Who needs templates? :)
add(10, stdout, 42); -> why this is wrong should be a compile-time error. In your case, it would very likely not even be a runtime error.
Post Reply