[sclug] C programming question and date on Linux
lug at assursys.co.uk
lug at assursys.co.uk
Sat Oct 25 09:05:36 UTC 2003
On Thu, 10 Apr 2003, Rick Payne wrote:
> --On Thursday, April 10, 2003 4:42 pm +0100 pieter claassen
> <pieter at openauth.co.uk> wrote:
>
> > Hello All,
> >
> > Here are two simple questions.
> > 1. Why does C on linux have such cool undocumented data types such as
> > u_int16_y and where are they documented? My Kernighan and Ritchie says
> > nothing about them. How do I know when I write a program which ones I am
> > supposed to use? Also, if I look through the /net/ethernet.h I get the
> > following declaration
>
> The u_intxx_t types seem to be a semi-standard - and may even be an
> official one. It helps to be specific when you're typing things that you
> want to be specific bit-sizes (ie. where 'int' just won't do).
the u_xxx_t types are defined in <linux/types.h> and are typedef'ed from the
definitions in <asm/types.h>
[snip]
> __attribute__((__packed__)) is a gross hack provided by gcc to allow you to
> break the normal rules 'C' would use when putting things into a structure.
> Its most commonly used when trying to make a structure that matches a
> packet or file format, as seen in your example. I use it all the time, but
> its still a gross hack.
Another common use for them is when you're creating structures to match the
layout of memory-mapped registers. The alternative would be doing something
like
char *regbase;
[...]
regbase=(char *)0xe2007000;
[...]
*(regbase+0)=(unsigned short)0xffff;
*(regbase+2)=(unsigned char)0xee;
*(regbase+3)=(unsigned int)0xc0edbabe;
Which is even more gross, IMHO (although, to be fair, if I was doing this
'for real', I would #define appropriate constants to allow the
slightly tidier-looking *(regbase+REGISTERA) code).
Similarly, defining datatypes with specific bit-lengths is necessary to
avoid the twin evils of a) having to write registers a character at a time -
some hardware is latched on writes and this plain won't work b) using a
driver on a machine with a different definition of 'int' say, and clobbering
two or more registers at the same time.
I've attached a couple of files to demonstrate what's going on - looking how
the C translates to x86 assembly is most instructive! (gcc -O2 -s testreg.c)
> Rick
Best Regards,
Alex (who's been hacking lots of C recently - Pup and xf86Wacom.c :)
--
Alex Butcher Brainbench MVP for Internet Security: www.brainbench.com
Bristol, UK Need reliable and secure network systems?
PGP/GnuPG ID:0x271fd950 <http://www.assursys.com/>
-------------- next part --------------
#include <linux/types.h>
struct regstruct
{
u_int32_t registera;
u_int8_t registerb;
u_int32_t registerc;
} __attribute__ ((__packed__));
typedef struct regstruct* regptr;
void write(int reg)
{
char *regbase=(char *)100000;
int offset=4;
*(regbase+offset)=(int)reg;
return;
}
int read(void)
{
char *regbase=(char *)100000;
int offset=4;
return((int)*(regbase+offset));
}
void writestruct(unsigned int rega, unsigned char regb, unsigned int regc)
{
struct regstruct *registers=(struct regstruct *)200000;
registers->registera=(unsigned int)rega;
registers->registerb=(unsigned char)regb;
registers->registerc=(unsigned int)regc;
return;
}
unsigned char registerb(void)
{
regptr registers=(regptr)300000;
return(registers->registerb);
}
-------------- next part --------------
.file "testreg.c"
.text
.align 2
.p2align 2,,3
.globl write
.type write, at function
write:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
movb %al, 100004
leave
ret
.Lfe1:
.size write,.Lfe1-write
.align 2
.p2align 2,,3
.globl read
.type read, at function
read:
pushl %ebp
movl %esp, %ebp
movsbl 100004,%eax
leave
ret
.Lfe2:
.size read,.Lfe2-read
.align 2
.p2align 2,,3
.globl writestruct
.type writestruct, at function
writestruct:
pushl %ebp
movl %esp, %ebp
movl 12(%ebp), %eax
movl 8(%ebp), %edx
movl %edx, 200000
movb %al, 200004
movl 16(%ebp), %eax
movl %eax, 200005
leave
ret
.Lfe3:
.size writestruct,.Lfe3-writestruct
.align 2
.p2align 2,,3
.globl registerb
.type registerb, at function
registerb:
pushl %ebp
movl %esp, %ebp
movzbl 300004, %eax
leave
ret
.Lfe4:
.size registerb,.Lfe4-registerb
.ident "GCC: (GNU) 3.2 20020903 (Red Hat Linux 8.0 3.2-7)"
More information about the Sclug
mailing list