Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does this code mean

Tags:

c

linux-kernel

I found a code segment. I do not understand it. It seems that the variable __rem is useless at all. The line below does not do any useful work yet:

(void)(((typeof((n)) *)0) == ((uint64_t *)0));   \

The whole code segment is as below:

#define do_div(n,base)  do{             \
    uint32_t __base = (base);           \
    uint32_t __rem;                 \
    (void)(((typeof((n)) *)0) == ((uint64_t *)0));   \
    if (((n) >> 32) == 0) {         \
        __rem = (uint32_t)(n) % __base;     \
        (n) = (uint32_t)(n) / __base;       \
    } else                      \
        __rem = __div64_32(&(n), __base);   \
    __rem;                      \
 }while(0)
/* Wrapper for do_div(). Doesn't modify dividend and returns
 * the result, not reminder.
 */
static inline uint64_t lldiv(uint64_t dividend, uint32_t divisor)
{
    uint64_t __res = dividend;
    do_div(__res, divisor);
    return(__res);
}

Why is the useless code here?

like image 710
user1651758 Avatar asked Aug 13 '15 11:08

user1651758


1 Answers

1. (void)(((typeof((n)) *)0) == ((uint64_t *)0));

See Linux/include/asm-generic/div64.h:

The unnecessary pointer compare is there to check for type safety (n must be 64bit)

Example:

n must be int, but it is short

void main()
{
    short n;
    (void)(((typeof((n)) *)0) == ((int *)0));
}

We get the warning: comparison of distinct pointer types lacks cast

Compiled with: gcc -o main main.c

Compiler version: gcc (GCC) 4.9.2 20141101 (Red Hat 4.9.2-1)

Conclusion:

The pointer compare is not useless. It generates a warning if the variable passed to do_div() has a wrong type.

2. __rem

The code surrounded by braces is a gcc statement-expressions. __rem is, so to say, the return value of do_div().

Example:

#include <stdio.h>

#define do_div(n,base)  ({ \
    int __rem = n % base;  \
    n /= base;             \
    __rem;                 \
})

int main()
{
    int a = 9;
    int b = 2;
    int c = 0;

    printf("%i / %i = ", a, b);
    c = do_div(a, b);
    printf("%i, reminder = %i\n", a, c);
    return 0;
}

Output: 9 / 2 = 4, reminder = 1

In the example above, c = do_div(a, b) is equivalent to c = ({int rem = a % b; a /= b; rem;}).

Conclusion:

__rem is not useless it is the "return value" of do_div().

like image 104
sergej Avatar answered Oct 23 '22 17:10

sergej