[Mac 10.7.1 Lion Intel-based x64 gcc4.2.1 xcode4.2 ]
Q:如何解决abs函数传入一个整形数最小值返回溢出的数?
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <limits.h> #define PRINT_D(intValue) printf(#intValue" is %d\n", (intValue)); #define PRINT_STR(str) printf(#str" is %s\n", (str)); int main() { int ret = abs(INT_MIN); PRINT_D(ret) return 0; }
ret is -2147483648
A:显然是溢出了。查看abs的源代码(可能实际会有区别:查看的是苹果开源代码libc-763.12):
int abs(j) int j; { return(j < 0 ? -j : j); }
unsigned abs(int n) { if(n == INT_MIN) return INT_MAX + 1U; return (n < 0 ? -n : n); }
Q:对于随机数,如何产生?
A:采用固定算法产生的随机数必然不能是真正意义上的随机,也称为伪随机数。不过再伪,有时也没关系了,上层觉得很像随机数就ok了。
很多随机数都采用如下的算法:
Rand_Number = (Rand_Seed * X + Y) mod Z
void srand(seed) u_int seed; { next = seed; }
static int do_rand(unsigned long *ctx) { #ifdef USE_WEAK_SEEDING /* * Historic implementation compatibility. * The random sequences do not vary much with the seed, * even with overflowing. */ return ((*ctx = *ctx * 1103515245 + 12345) % ((u_long)RAND_MAX + 1)); #else /* !USE_WEAK_SEEDING */ /* * Compute x = (7^5 * x) mod (2^31 - 1) * without overflowing 31 bits: * (2^31 - 1) = 127773 * (7^5) + 2836 * From "Random number generators: good ones are hard to find", * Park and Miller, Communications of the ACM, vol. 31, no. 10, * October 1988, p. 1195. */ long hi, lo, x; /* Can't be initialized with 0, so use another value. */ if (*ctx == 0) *ctx = 123459876; hi = *ctx / 127773; lo = *ctx % 127773; x = 16807 * lo - 2836 * hi; if (x < 0) x += 0x7fffffff; return ((*ctx = x) % ((u_long)RAND_MAX + 1)); #endif /* !USE_WEAK_SEEDING */ } int rand() { return (do_rand(&next)); }
Q:c库内部出现的错误或者异常,如何让上层获取到?
A:可以采用全局变量保存的方式或者保存在各个线程的TLS区域。采用全局变量在多线程的时候会出现问题,TLS可以很好地解决这个问题。另外,也可能在各个可能出现异常函数加上一个参数专门保存异常信息,当然这样会导致函数接口不简洁。下面是苹果对errno的实现:
extern int errno; int *__error(void) { pthread_t self = pthread_self(); /* If we're not a detached pthread, just return the global errno */ if ((self == (pthread_t)0) || (self->sig != _PTHREAD_SIG)) { return &errno; } return &self->err_no; } int cthread_errno(void) { return *__error(); }
typedef struct _pthread { long sig; /* Unique signature for this structure */ struct __darwin_pthread_handler_rec *__cleanup_stack; pthread_lock_t lock; /* Used for internal mutex on structure */ uint32_t detached:8, inherit:8, policy:8, freeStackOnExit:1, newstyle:1, kernalloc:1, schedset:1, wqthread:1, wqkillset:1, pad:2; size_t guardsize; /* size in bytes to guard stack overflow */ #if !defined(__LP64__) int pad0; /* for backwards compatibility */ #endif struct sched_param param; uint32_t cancel_error; #if defined(__LP64__) uint32_t cancel_pad; /* pad value for alignment */ #endif struct _pthread *joiner; #if !defined(__LP64__) int pad1; /* for backwards compatibility */ #endif void *exit_value; semaphore_t death; /* pthread_join() uses this to wait for death's call */ mach_port_t kernel_thread; /* kernel thread this thread is bound to */ void *(*fun)(void*);/* Thread start routine */ void *arg; /* Argment for thread start routine */ int cancel_state; /* Whether thread can be cancelled */ int err_no; /* thread-local errno */ void *tsd[_EXTERNAL_POSIX_THREAD_KEYS_MAX + _INTERNAL_POSIX_THREAD_KEYS_MAX]; /* Thread specific data */ void *stackaddr; /* Base of the stack (is aligned on vm_page_size boundary */ size_t stacksize; /* Size of the stack (is a multiple of vm_page_size and >= PTHREAD_STACK_MIN) */ mach_port_t reply_port; /* Cached MiG reply port */ #if defined(__LP64__) int pad2; /* for natural alignment */ #endif void *cthread_self; /* cthread_self() if somebody calls cthread_set_self() */ /* protected by list lock */ uint32_t childrun:1, parentcheck:1, childexit:1, pad3:29; #if defined(__LP64__) int pad4; /* for natural alignment */ #endif TAILQ_ENTRY(_pthread) plist; void * freeaddr; size_t freesize; mach_port_t joiner_notify; char pthread_name[MAXTHREADNAMESIZE]; /* including nulll the name */ int max_tsd_key; void * cur_workq; void * cur_workitem; uint64_t thread_id; } *pthread_t;
Q: atexit函数该如何实现?
A:需要一个可以保存数个注册的函数指针的结构,当应用程序结束前可以从中取出函数,按特定的顺序执行。
struct atexit { struct atexit *next; /* next in list */ int ind; /* next index in this table */ struct atexit_fn { int fn_type; /* ATEXIT_? from above */ union { void (*std_func)(void); void (*cxa_func)(void *); #ifdef __BLOCKS__ void (^block)(void); #endif /* __BLOCKS__ */ } fn_ptr; /* function pointer */ void *fn_arg; /* argument for CXA callback */ void *fn_dso; /* shared module handle */ } fns[ATEXIT_SIZE]; /* the table itself */ };
static struct atexit __atexit0;
Q: exit函数在何时调用atexit注册的函数呢?
A:当然在调用系统退出应用程序前执行它。
/* * Exit, flushing stdio buffers if necessary. */ void exit(status) int status; { __cxa_finalize(NULL); if (__cleanup) (*__cleanup)(); __exit(status); }
void __cxa_finalize(void *dso) { struct atexit *p; struct atexit_fn fn; int n; _MUTEX_LOCK(&atexit_mutex); for (p = __atexit; p; p = p->next) { for (n = p->ind; --n >= 0;) { if (p->fns[n].fn_type == ATEXIT_FN_EMPTY) continue; /* already been called */ if (dso != NULL && dso != p->fns[n].fn_dso) continue; /* wrong DSO */ fn = p->fns[n]; /* Mark entry to indicate that this particular handler has already been called. */ p->fns[n].fn_type = ATEXIT_FN_EMPTY; _MUTEX_UNLOCK(&atexit_mutex); /* Call the function of correct type. */ if (fn.fn_type == ATEXIT_FN_CXA) fn.fn_ptr.cxa_func(fn.fn_arg); else if (fn.fn_type == ATEXIT_FN_STD) fn.fn_ptr.std_func(); _MUTEX_LOCK(&atexit_mutex); } } _MUTEX_UNLOCK(&atexit_mutex); }
A:采用fork方式创建一个子进程,如果返回父进程执行,将等待子进程完成;如果进入子进程,使用execl加载子进程镜像来执行。如下代码:
int __system(command) const char *command; { pid_t pid, savedpid; int pstat; struct sigaction ign, intact, quitact; sigset_t newsigblock, oldsigblock; if (!command) /* just checking... */ return(1); /* * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save * existing signal dispositions. */ ign.sa_handler = SIG_IGN; (void)sigemptyset(&ign.sa_mask); ign.sa_flags = 0; (void)_sigaction(SIGINT, &ign, &intact); (void)_sigaction(SIGQUIT, &ign, &quitact); (void)sigemptyset(&newsigblock); (void)sigaddset(&newsigblock, SIGCHLD); (void)_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); switch(pid = fork()) { case -1: /* error */ break; case 0: /* child */ /* * Restore original signal dispositions and exec the command. */ (void)_sigaction(SIGINT, &intact, NULL); (void)_sigaction(SIGQUIT, &quitact, NULL); (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL); _exit(127); default: /* parent */ savedpid = pid; do { pid = _wait4(savedpid, &pstat, 0, (struct rusage *)0); } while (pid == -1 && errno == EINTR); break; } (void)_sigaction(SIGINT, &intact, NULL); (void)_sigaction(SIGQUIT, &quitact, NULL); (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); return(pid == -1 ? -1 : pstat); }
xichen
2012-6-2 15:52:11