C puzzles详解【46-50题】

第四十六题

What does the following macro do? 
  #define ROUNDUP(x,n) ((x+n-1)&(~(n-1)))
题目讲解:
参考:http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=814501
用于内存对齐,n为2的幂。

第四十七题

Most of the C programming books, give the following example for the definition of macros. 
  #define isupper(c) (((c) >= 'A') && ((c) <= 'Z'))
But there would be a serious problem with the above definition of macro, if it is used as follows (what is the problem??) 
  char c;
  /* ... */
  if(isupper(c++))
  {
      /* ... */
  }
But most of the libraries implement the isupper (declared in ctypes.h) as a macro (without any side effects). Find out how isupper() is implemented on your system.
知识点讲解:
Linux内核中isupper的实现见lib/ctype.c和include/linux/ctype.h。
ctype.h代码如下:
#ifndef _LINUX_CTYPE_H
#define _LINUX_CTYPE_H

/*
 * NOTE! This ctype does not handle EOF like the standard C
 * library is required to.
 */

#define _U    0x01    /* upper */
#define _L    0x02    /* lower */
#define _D    0x04    /* digit */
#define _C    0x08    /* cntrl */
#define _P    0x10    /* punct */
#define _S    0x20    /* white space (space/lf/tab) */
#define _X    0x40    /* hex digit */
#define _SP    0x80    /* hard space (0x20) */

extern const unsigned char _ctype[];

#define __ismask(x) (_ctype[(int)(unsigned char)(x)])

#define isalnum(c)    ((__ismask(c)&(_U|_L|_D)) != 0)
#define isalpha(c)    ((__ismask(c)&(_U|_L)) != 0)
#define iscntrl(c)    ((__ismask(c)&(_C)) != 0)
#define isdigit(c)    ((__ismask(c)&(_D)) != 0)
#define isgraph(c)    ((__ismask(c)&(_P|_U|_L|_D)) != 0)
#define islower(c)    ((__ismask(c)&(_L)) != 0)
#define isprint(c)    ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
#define ispunct(c)    ((__ismask(c)&(_P)) != 0)
/* Note: isspace() must return false for %NUL-terminator */
#define isspace(c)    ((__ismask(c)&(_S)) != 0)
#define isupper(c)    ((__ismask(c)&(_U)) != 0)
#define isxdigit(c)    ((__ismask(c)&(_D|_X)) != 0)

#define isascii(c) (((unsigned char)(c))<=0x7f)
#define toascii(c) (((unsigned char)(c))&0x7f)

static inline unsigned char __tolower(unsigned char c)
{
    if (isupper(c))
        c -= 'A'-'a';
    return c;
}

static inline unsigned char __toupper(unsigned char c)
{
    if (islower(c))
        c -= 'a'-'A';
    return c;
}

#define tolower(c) __tolower(c)
#define toupper(c) __toupper(c)

#endif
ctype.c代码如下:
/*
 *  linux/lib/ctype.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */

#include <linux/ctype.h>
#include <linux/module.h>

const unsigned char _ctype[] = {
_C,_C,_C,_C,_C,_C,_C,_C,                /* 0-7 */
_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,            /* 8-15 */
_C,_C,_C,_C,_C,_C,_C,_C,                /* 16-23 */
_C,_C,_C,_C,_C,_C,_C,_C,                /* 24-31 */
_S|_SP,_P,_P,_P,_P,_P,_P,_P,                /* 32-39 */
_P,_P,_P,_P,_P,_P,_P,_P,                /* 40-47 */
_D,_D,_D,_D,_D,_D,_D,_D,                /* 48-55 */
_D,_D,_P,_P,_P,_P,_P,_P,                /* 56-63 */
_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,        /* 64-71 */
_U,_U,_U,_U,_U,_U,_U,_U,                /* 72-79 */
_U,_U,_U,_U,_U,_U,_U,_U,                /* 80-87 */
_U,_U,_U,_P,_P,_P,_P,_P,                /* 88-95 */
_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,        /* 96-103 */
_L,_L,_L,_L,_L,_L,_L,_L,                /* 104-111 */
_L,_L,_L,_L,_L,_L,_L,_L,                /* 112-119 */
_L,_L,_L,_P,_P,_P,_P,_C,                /* 120-127 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,            /* 128-143 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,            /* 144-159 */
_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,    /* 160-175 */
_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,    /* 176-191 */
_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,    /* 192-207 */
_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,    /* 208-223 */
_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,    /* 224-239 */
_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};    /* 240-255 */

EXPORT_SYMBOL(_ctype);
_ctype数组中的每个元素的值对应ASCII码为0-255的每个字符的类型,以字符的ASCII码为索引即可获取到相应字符的类型。

第四十八题

I hope you know that ellipsis (...) is used to specify variable number of arguments to a function. (What is the function prototype declaration for printf?) What is wrong with the following delcaration? 
  int VarArguments(...)
  {
      /*....*/
      return 0;
  }
知识点讲解:
对于带有不定参数的函数,用va_start,va_arg,va_end对参数进行索引,内核代码中va_*系列函数的实现在
include/acpi/platform/acenv.h中

#ifndef va_arg

#ifndef _VALIST
#define _VALIST
typedef char *va_list;
#endif                /* _VALIST */

/*
 * Storage alignment properties
 */
#define  _AUPBND                (sizeof (acpi_native_int) - 1)
#define  _ADNBND                (sizeof (acpi_native_int) - 1)

/*
 * Variable argument list macro definitions
 */
#define _bnd(X, bnd)            (((sizeof (X)) + (bnd)) & (~(bnd)))
#define va_arg(ap, T)           (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
#define va_end(ap)              (void) 0
#define va_start(ap, A)         (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))

#endif                /* va_arg */
由如上定义可知,va_start返回第一个不定参数的地址,va_arg返回下一个不定参数的地址,va_end用来销毁ap。
va_start和va_end总是成对使用。
va_start获取第一个不定参数的地址时,必须知道最后一个固定参数A的地址,即函数必须提供至少一个固定参数。
故定义形如VarArguments(...)的函数是不正确的。

第四十九题

Write a C program to find the smallest of three integers, without using any of the comparision operators.
题目讲解:
参考:
http://www.geeksforgeeks.org/smallest-of-three-integers-without-comparison-operators/
方法一:
int smallest(int x, int y, int z)
{
  int c = 0;
  while ( x && y && z )
  {
      x--;  y--; z--; c++;
  }
  return c;
}
方法二:
#define CHAR_BIT 8

/*Function to find minimum of x and y*/
int min(int x, int y)
{
  return  y + ((x - y) & ((x - y) >>
            (sizeof(int) * CHAR_BIT - 1)));
}

/* Function to find minimum of 3 numbers x, y and z*/
int smallest(int x, int y, int z)
{
    return min(x, min(y, z));
}
方法三:
// Using division operator to find minimum of three numbers
int smallest(int x, int y, int z)
{
    if (!(y/x))  // Same as "if (y < x)"
        return (!(y/z))? y : z;
    return (!(x/z))? x : z;
}

 

第五十题

What does the format specifier %n of printf function do?
参考:
http://www.geeksforgeeks.org/g-fact-31/
如:
printf("geeks for %ngeeks ", &c);
将%n之前的字符数赋值给c。
posted @ 2014-09-23 21:51  tanghuimin0713  阅读(517)  评论(0编辑  收藏  举报