writing usb drivers under 8.x

Jim Bryant kc5vdj.freebsd at gmail.com
Mon Aug 30 02:20:10 UTC 2010


well, i can't speak for K&R 1978, as i can't currently find my copy, 
but, for a quick brush up, you might want to read pages 80 and 81 from 
K&R 2nd Ed. 1988.

your idea that the preprocessor will evaluate

#define thirtytwok (1<<15)

into 0x8000

at compile time is totally incorrect, and in fact wouldn't be in 
compliance with standards.  i have iso and fips handy, care for quotes?

microsoft used to do compile-time eval of preprocessor statements 
instead of substitution, but that was implementation-specific and 
non-standard.

 From K&R, 2nd Ed. pp80-81 (1988):

4.11.2 Macro Substitution

A definition has the form

#define name replacement text

It calls for a macro substitution of the simplest kind - subsequent 
occurrences of the token
name will be replaced by the replacement text. The name in a #define has 
the same form as a
variable name; the replacement text is arbitrary. Normally the 
replacement text is the rest of
the line, but a long definition may be continued onto several lines by 
placing a \ at the end of
each line to be continued. The scope of a name defined with #define is 
from its point of
definition to the end of the source file being compiled. A definition 
may use previous
definitions. Substitutions are made only for tokens, and do not take 
place within quoted
strings. For example, if YES is a defined name, there would be no 
substitution in
printf("YES") or in YESMAN.

Any name may be defined with any replacement text. For example

#define forever for (;;) /* infinite loop */

defines a new word, forever, for an infinite loop.

It is also possible to define macros with arguments, so the replacement 
text can be different
for different calls of the macro. As an example, define a macro called max:

#define max(A, B) ((A) > (B) ? (A) : (B))

Although it looks like a function call, a use of max expands into 
in-line code. Each occurrence
of a formal parameter (here A or B) will be replaced by the 
corresponding actual argument.

Thus the line

x = max(p+q, r+s);

will be replaced by the line

x = ((p+q) > (r+s) ? (p+q) : (r+s));

So long as the arguments are treated consistently, this macro will serve 
for any data type;
there is no need for different kinds of max for different data types, as 
there would be with
functions.

81

If you examine the expansion of max, you will notice some pitfalls. The 
expressions are
evaluated twice; this is bad if they involve side effects like increment 
operators or input and
output. For instance

max(i++, j++) /* WRONG */

will increment the larger twice. Some care also has to be taken with 
parentheses to make sure
the order of evaluation is preserved; consider what happens when the macro

#define square(x) x * x /* WRONG */

is invoked as square(z+1).

Nonetheless, macros are valuable. One practical example comes from 
<stdio.h>, in which
getchar and putchar are often defined as macros to avoid the run-time 
overhead of a
function call per character processed. The functions in <ctype.h> are 
also usually
implemented as macros.

Names may be undefined with #undef, usually to ensure that a routine is 
really a function, not
a macro:

#undef getchar
int getchar(void) { ... }

Formal parameters are not replaced within quoted strings. If, however, a 
parameter name is
preceded by a # in the replacement text, the combination will be 
expanded into a quoted string
with the parameter replaced by the actual argument. This can be combined 
with string
concatenation to make, for example, a debugging print macro:

#define dprint(expr) printf(#expr " = %g\n", expr)

When this is invoked, as in

dprint(x/y)

the macro is expanded into

printf("x/y" " = &g\n", x/y);

and the strings are concatenated, so the effect is

printf("x/y = &g\n", x/y);

Within the actual argument, each " is replaced by \" and each \ by \\, 
so the result is a legal
string constant.

The preprocessor operator ## provides a way to concatenate actual 
arguments during macro
expansion. If a parameter in the replacement text is adjacent to a ##, 
the parameter is replaced
by the actual argument, the ## and surrounding white space are removed, 
and the result is rescanned.

For example, the macro paste concatenates its two arguments:

#define paste(front, back) front ## back

so paste(name, 1) creates the token name1.

The rules for nested uses of ## are arcane; further details may be found 
in Appendix A.
Exercise 4-14. Define a macro swap(t,x,y) that interchanges two 
arguments of type t.
(Block structure will help.)

Jim Bryant wrote:
> ummmm.. you were saying???
>
> 8:58:44pm  orb(19): cat bs3.c
> #include <stdio.h>
>
> int main(void)
> {
>  int toshiftornottoshift = 0x8000;
>
>  printf("%d\n", toshiftornottoshift);
>
>  return(0);
> }
> 8:58:48pm  orb(20): cc -S -O2 -o bs3.s bs3.c
> 8:58:53pm  orb(21): cat bs3.s
>        .file   "bs3.c"
>        .section        .rodata.str1.1,"aMS", at progbits,1
> .LC0:
>        .string "%d\n"
>        .text
>        .p2align 4,,15
> .globl main
>        .type   main, @function
> main:
> .LFB3:
>        subq    $8, %rsp
> .LCFI0:
> /*
> *      this doesn't look like the compiler generates a shift to me.
> */
>        movl    $32768, %esi
>        movl    $.LC0, %edi
>        xorl    %eax, %eax
>        call    printf
>        xorl    %eax, %eax
>        addq    $8, %rsp
>        ret
> .LFE3:
>        .size   main, .-main
>        .section        .eh_frame,"a", at progbits
> .Lframe1:
>        .long   .LECIE1-.LSCIE1
> .LSCIE1:
>        .long   0x0
>        .byte   0x1
>        .string "zR"
>        .uleb128 0x1
>        .sleb128 -8
>        .byte   0x10
>        .uleb128 0x1
>        .byte   0x3
>        .byte   0xc
>        .uleb128 0x7
>        .uleb128 0x8
>        .byte   0x90
>        .uleb128 0x1
>        .align 8
> .LECIE1:
> .LSFDE1:
>        .long   .LEFDE1-.LASFDE1
> .LASFDE1:
>        .long   .LASFDE1-.Lframe1
>        .long   .LFB3
>        .long   .LFE3-.LFB3
>        .uleb128 0x0
>        .byte   0x4
>        .long   .LCFI0-.LFB3
>        .byte   0xe
>        .uleb128 0x10
>        .align 8
> .LEFDE1:
>        .ident  "GCC: (GNU) 4.2.1 20070719  [FreeBSD]"
>
> perryh at pluto.rain.com wrote:
>> Jim Bryant <kc5vdj.freebsd at gmail.com> wrote:
>>
>>  
>>> what kind of idiot defines a constant assignment for a 32k buffer as 
>>> a 15 bit left shift of 1?
>>>
>>> clever, yes.  but in production, stupid.
>>>
>>> a constant should be just that, a constant, and thus require no 
>>> computation at runtime.
>>>     
>>
>> Er, did you bother to look at the generated code before spouting off?
>> Most compilers, even as far back as K&R 1st edition, will compute
>> constant expressions like that at compile time.
>>
>>   
>


More information about the freebsd-usb mailing list