C library (II)-small talk C language (18)

Source: Internet
Author: User

[Mac 10.7.1 lion intel-based x64 gcc4.2.1 xcode4.2]

Q: How can I solve the problem of returning the overflow number when an integer is input to the ABS function?

#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;}

Output:

ret is -2147483648

A: Apparently, it is overflow. View the ABS source code (may actually be different: view is apple open source code libc-763.12 ):

intabs(j)int j;{return(j < 0 ? -j : j);}

Obviously, the result will inevitably overflow. One solution is to separately process the maximum negative value and increase the maximum value range of the return value type, as shown below:

unsigned abs(int n){    if(n == INT_MIN)        return INT_MAX + 1U;    return (n < 0 ? -n : n);}

Q: How do I generate random numbers?

A: random numbers produced by fixed algorithms cannot be real random numbers, also known as pseudo-random numbers. However, it may be okay if it is a pseudo-random number on the upper layer.

Many random numbers use the following algorithm:

 

Rand_Number = (Rand_Seed * X + Y) mod Z

See the source code below:

voidsrand(seed)u_int seed;{next = seed;}
static intdo_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 */}intrand(){return (do_rand(&next));}

Q: How can I obtain the error or exception in the C library from the upper layer?

A: global variables can be saved or saved in the TLS area of each thread. The problem may occur when using global variables in multiple threads. TLS can solve this problem well. In addition, you may add a parameter to each function that may cause exceptions to save the exception information. Of course, this will make the function interface not concise. The following is Apple's implementation of 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();}

It can be seen that each thread has a separate error message, which supports multithreading. Note the following pthread_t structure:

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_tdetached: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 */#endifstruct sched_param param;uint32_tcancel_error;#if defined(__LP64__)uint32_tcancel_pad;/* pad value for alignment */#endifstruct _pthread *joiner;#if !defined(__LP64__)intpad1;/* for backwards compatibility */#endifvoid           *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__)        intpad2;/* for natural alignment */#endifvoid           *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__)intpad4;/* for natural alignment */#endifTAILQ_ENTRY(_pthread) plist;void *freeaddr;size_tfreesize;mach_port_tjoiner_notify;charpthread_name[MAXTHREADNAMESIZE];/* including nulll the name */        intmax_tsd_key;void *cur_workq;void * cur_workitem;uint64_t thread_id;} *pthread_t;

Q: How to Implement the atexit function?

A: You need a structure that can save several registered function pointers. When the application ends, you can retrieve the functions and execute them in a specific order.

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 */};

Of course, atexit is a process. You can use static variables to save this structure:

static struct atexit __atexit0;

Q: When will the exit function call the function registered by atexit?

A: Of course, execute it before calling the system to exit the application.

/* * Exit, flushing stdio buffers if necessary. */voidexit(status)int status;{__cxa_finalize(NULL);if (__cleanup)(*__cleanup)();__exit(status);}

The _ cxa_finalize function executes the previously registered function atexit:

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);}

Q: How does the system function implement execution of an executable file?

A: create a sub-process in fork mode. If the execution of the parent process is returned, it will wait until the sub-process is completed. If the sub-process enters, execl is used to load the sub-process image for execution. The following code:

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

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.