HP_Socket学习01 Linux

#、##、__VA_ARGS__和##__VA_ARGS__的作用

https://blog.csdn.net/q2519008/article/details/80934815
##__VA_ARGS__ 宏前面加上##的作用在于,当可变参数的个数为0时,这里的##起到把前面多余的","去掉的作用,否则会编译出错

sysconf

获得系统配置信息
DESCRIPTION
       POSIX  allows  an application to test at compile or run time whether certain options are supported, or what the value is of certain
       configurable constants or limits.

       At compile time this is done by including <unistd.h> and/or <limits.h> and testing the value of certain macros.

       At run time, one can ask for numerical values using the present function sysconf().  One can ask  for  numerical  values  that  may
       depend  on  the  filesystem  in which a file resides using fpathconf(3) and pathconf(3).  One can ask for string values using conf‐
       str(3).

       The values obtained from these functions are system configuration constants.  They do not change during the lifetime of a process.

       For options, typically, there is a constant _POSIX_FOO that may be defined in <unistd.h>.  If it is undefined, one  should  ask  at
       run  time.   If  it is defined to -1, then the option is not supported.  If it is defined to 0, then relevant functions and headers
       exist, but one has to ask at run time what degree of support is available.  If it is defined to a value other than -1  or  0,  then
       the  option  is  supported.   Usually the value (such as 200112L) indicates the year and month of the POSIX revision describing the
       option.  Glibc uses the value 1 to indicate support as long as the POSIX revision has not been published yet.  The sysconf()  argu‐
       ment will be _SC_FOO.  For a list of options, see posixoptions(7).

       For  variables  or  limits,  typically,  there  is  a  constant  _FOO, maybe defined in <limits.h>, or _POSIX_FOO, maybe defined in
       <unistd.h>.  The constant will not be defined if the limit is unspecified.  If the constant  is  defined,  it  gives  a  guaranteed
       value,  and  a  greater  value  might  actually be supported.  If an application wants to take advantage of values which may change
       between systems, a call to sysconf() can be made.  The sysconf() argument will be _SC_FOO.
翻译:
描述

POSIX允许应用程序在编译或运行时测试是否支持某些选项,或者哪些值是确定的。可配置常量或限制。
在编译时,这是通过包括<unistd.h>和/或<limits.h>并测试某些宏的值来完成的。
在运行时,可以使用当前函数sysconf()请求数值。我们可以要求数值取决于使用fpathconf(3)和pathconf(3)存放文件的文件系统。可以使用conf‐请求字符串值STR(3)。
从这些函数中获得的值是系统配置常数。它们在进程的生命周期中不会改变。
对于选项,通常有一个常量posix foo可以在<unistd.h>中定义。如果未定义,应在运行时间。如果定义为-1,则不支持该选项。如果定义为0,则相关函数和头存在,但必须在运行时询问可用的支持程度。如果定义的值不是-1或0,则支持该选项。通常,值(例如200112L)表示描述选择权。glibc使用值1表示支持,只要posix版本尚未发布。sysconf()参数
我们将为您提供服务。有关选项列表,请参见posixOptions(7)。
对于变量或限制,通常有一个常量foo,可以在<limits.h>中定义,也可以在
< UNITST.H>如果未指定限制,则不会定义常量。如果定义了常量,它将给出一个有保证的值,实际上可能支持更大的值。如果应用程序希望利用可能发生更改的值在系统之间,可以调用sysconf()。sysconf()参数将是_sc_foo。
参数看man page
RETURN VALUE
       The return value of sysconf() is one of the following:

       *  On  error,  -1 is returned and errno is set to indicate the cause of
          the error (for example, EINVAL, indicating that name is invalid).

       *  If name corresponds to a maximum or minimum limit, and that limit is
          indeterminate, -1 is returned and errno is not changed.  (To distin‐
          guish an indeterminate limit from an error, set errno to zero before
          the  call,  and  then  check  whether  errno  is  nonzero when -1 is
          returned.)

       *  If name corresponds to an option, a positive value  is  returned  if
          the  option  is  supported,  and -1 is returned if the option is not
          supported.

       *  Otherwise, the current value of the option  or  limit  is  returned.
          This value will not be more restrictive than the corresponding value
          that was described to the application in  <unistd.h>  or  <limits.h>
          when the application was compiled.

ERRORS
       EINVAL name is invalid.

sysconf(_SC_NPROCESSORS_ONLN)

_SC_NPROCESSORS_CONF
              The    number    of    processors    configured.     See    also
              get_nprocs_conf(3).
获得处理器的数量

sysinfo

sysinfo()返回有关内存和交换使用情况以及平均负载的某些统计信息。
RETURN VALUE
       On success, sysinfo() returns zero.  On error, -1 is returned, and errno is set to indicate the cause of the error.

ERRORS
       EFAULT info is not a valid address.

VERSIONS
       sysinfo() first appeared in Linux 0.98.pl6.

CONFORMING TO
       This function is Linux-specific, and should not be used in programs intended to be portable.

NOTES
       All of the information provided by this system call is also available via /proc/meminfo and /proc/loadavg.

get_nprocs

描述
       The function get_nprocs_conf() returns the number of processors config‐
       ured by the operating system.

       The function get_nprocs() returns the number  of  processors  currently
       available  in the system.  This may be less than the number returned by
       get_nprocs_conf() because processors may be offline (e.g., on  hotplug‐
       gable systems).
函数get_nprocs_conf()返回配置‐的处理器数量由操作系统确定。
函数get_nprocs()返回当前处理器的数量在系统中可用。这可能小于返回的数字get_nprocs_conf()因为处理器可能离线(例如,在热插拔‐上)山墙系统)。

目前这些功能的实现相当昂贵,
因为它们每次都在/sys文件系统中打开和解析文件被称为。
下面的sysconf(3)调用使用了上面记录的函数此页面返回相同的信息。

       #include <stdlib.h>
       #include <stdio.h>
       #include <sys/sysinfo.h>

       int
       main(int argc, char *argv[])
       {
           printf("This system has %d processors configured and "
                   "%d processors available.\n",
                   get_nprocs_conf(), get_nprocs());
           exit(EXIT_SUCCESS);
       }

getpagesize

DESCRIPTION
       The function getpagesize() returns the number  of  bytes  in  a  memory
       page, where "page" is a fixed-length block, the unit for memory alloca-
       tion and file mapping performed by mmap(2).
       返回当前机器一个内存页的字节数
NOTES
       Portable applications should employ  sysconf(_SC_PAGESIZE)  instead  of
       getpagesize():(可移植程序应该使用:)

           #include <unistd.h>
           long sz = sysconf(_SC_PAGESIZE);

getpid

DESCRIPTION
       getpid() returns the process ID of the calling process.  (This is often
       used by routines that generate unique temporary filenames.)

       getppid() returns the process ID of the parent of the calling process.

ERRORS
       These functions are always successful.

syscall(__NR_gettid)


DESCRIPTION    
       syscall() 执行一个系统调用,根据指定的参数number和所有系统调用的汇编语言接口来确定调用哪个系统调用。
Linux中,每个进程有一个pid,类型pid_t,由getpid()取得。Linux下的POSIX线程也有一个id,类型 pthread_t,由pthread_self()取得,该id由线程库维护,其id空间是各个进程独立的(即不同进程中的线程可能有相同的id)。Linux中的POSIX线程库实现的线程其实也是一个进程(LWP),只是该进程与主进程(启动线程的进程)共享一些资源而已,比如代码段,数据段等。
有时候我们可能需要知道线程的真实pid。比如进程P1要向另外一个进程P2中的某个线程发送信号时,既不能使用P2的pid,更不能使用线程的pthread id,而只能使用该线程的真实pid,称为tid。
有一个函数gettid()可以得到tid,但glibc并没有实现该函数,只能通过Linux的系统调用syscall来获取。

头文件定义:
/* Generated at libc build time from kernel syscall list. */

#ifndef _SYSCALL_H
# error "Never use <bits/syscall.h> directly; include <sys/syscall.h> instead."
#endif

#include <bits/wordsize.h>

#define SYS__sysctl __NR__sysctl
#define SYS_access __NR_access
#define SYS_acct __NR_acct
#define SYS_add_key __NR_add_key
#define SYS_adjtimex __NR_adjtimex
#define SYS_afs_syscall __NR_afs_syscall
#define SYS_alarm __NR_alarm
#define SYS_brk __NR_brk
#define SYS_capget __NR_capget
#define SYS_capset __NR_capset
#define SYS_chdir __NR_chdir
#define SYS_chmod __NR_chmod
#define SYS_chown __NR_chown
#define SYS_chroot __NR_chroot
#define SYS_clock_getres __NR_clock_getres
#define SYS_clock_gettime __NR_clock_gettime
#define SYS_clock_nanosleep __NR_clock_nanosleep
#define SYS_clock_settime __NR_clock_settime
#define SYS_clone __NR_clone
#define SYS_close __NR_close
#define SYS_creat __NR_creat
#define SYS_create_module __NR_create_module
#define SYS_delete_module __NR_delete_module
#define SYS_dup __NR_dup
#define SYS_dup2 __NR_dup2
#define SYS_epoll_create __NR_epoll_create
#define SYS_epoll_ctl __NR_epoll_ctl
#define SYS_epoll_wait __NR_epoll_wait
#define SYS_eventfd __NR_eventfd
#define SYS_execve __NR_execve
#define SYS_exit __NR_exit
#define SYS_exit_group __NR_exit_group
#define SYS_faccessat __NR_faccessat
#define SYS_fadvise64 __NR_fadvise64
#define SYS_fallocate __NR_fallocate
#define SYS_fchdir __NR_fchdir
#define SYS_fchmod __NR_fchmod
#define SYS_fchmodat __NR_fchmodat
#define SYS_fchown __NR_fchown
#define SYS_fchownat __NR_fchownat
#define SYS_fcntl __NR_fcntl
#define SYS_fdatasync __NR_fdatasync
#define SYS_fgetxattr __NR_fgetxattr
#define SYS_flistxattr __NR_flistxattr
#define SYS_flock __NR_flock
#define SYS_fork __NR_fork
#define SYS_fremovexattr __NR_fremovexattr
#define SYS_fsetxattr __NR_fsetxattr
#define SYS_fstat __NR_fstat
#define SYS_fstatfs __NR_fstatfs
#define SYS_fsync __NR_fsync
#define SYS_ftruncate __NR_ftruncate
#define SYS_futex __NR_futex
#define SYS_futimesat __NR_futimesat
#define SYS_get_kernel_syms __NR_get_kernel_syms
#define SYS_get_mempolicy __NR_get_mempolicy
#define SYS_get_robust_list __NR_get_robust_list
#define SYS_get_thread_area __NR_get_thread_area
#define SYS_getcwd __NR_getcwd
#define SYS_getdents __NR_getdents
#define SYS_getdents64 __NR_getdents64
#define SYS_getegid __NR_getegid
#define SYS_geteuid __NR_geteuid
#define SYS_getgid __NR_getgid
#define SYS_getgroups __NR_getgroups
#define SYS_getitimer __NR_getitimer
#define SYS_getpgid __NR_getpgid
#define SYS_getpgrp __NR_getpgrp
#define SYS_getpid __NR_getpid
#define SYS_getpmsg __NR_getpmsg
#define SYS_getppid __NR_getppid
#define SYS_getpriority __NR_getpriority
#define SYS_getresgid __NR_getresgid
#define SYS_getresuid __NR_getresuid
#define SYS_getrlimit __NR_getrlimit
#define SYS_getrusage __NR_getrusage
#define SYS_getsid __NR_getsid
#define SYS_gettid __NR_gettid
#define SYS_gettimeofday __NR_gettimeofday
#define SYS_getuid __NR_getuid
#define SYS_getxattr __NR_getxattr
#define SYS_init_module __NR_init_module
#define SYS_inotify_add_watch __NR_inotify_add_watch
#define SYS_inotify_init __NR_inotify_init
#define SYS_inotify_rm_watch __NR_inotify_rm_watch
#define SYS_io_cancel __NR_io_cancel
#define SYS_io_destroy __NR_io_destroy
#define SYS_io_getevents __NR_io_getevents
#define SYS_io_setup __NR_io_setup
#define SYS_io_submit __NR_io_submit
#define SYS_ioctl __NR_ioctl
#define SYS_ioperm __NR_ioperm
#define SYS_iopl __NR_iopl
#define SYS_ioprio_get __NR_ioprio_get
#define SYS_ioprio_set __NR_ioprio_set
#define SYS_kexec_load __NR_kexec_load
#define SYS_keyctl __NR_keyctl
#define SYS_kill __NR_kill
#define SYS_lchown __NR_lchown
#define SYS_lgetxattr __NR_lgetxattr
#define SYS_link __NR_link
#define SYS_linkat __NR_linkat
#define SYS_listxattr __NR_listxattr
#define SYS_llistxattr __NR_llistxattr
#define SYS_lookup_dcookie __NR_lookup_dcookie
#define SYS_lremovexattr __NR_lremovexattr
#define SYS_lseek __NR_lseek
#define SYS_lsetxattr __NR_lsetxattr
#define SYS_lstat __NR_lstat
#define SYS_madvise __NR_madvise
#define SYS_mbind __NR_mbind
#define SYS_migrate_pages __NR_migrate_pages
#define SYS_mincore __NR_mincore
#define SYS_mkdir __NR_mkdir
#define SYS_mkdirat __NR_mkdirat
#define SYS_mknod __NR_mknod
#define SYS_mknodat __NR_mknodat
#define SYS_mlock __NR_mlock
#define SYS_mlockall __NR_mlockall
#define SYS_mmap __NR_mmap
#define SYS_modify_ldt __NR_modify_ldt
#define SYS_mount __NR_mount
#define SYS_move_pages __NR_move_pages
#define SYS_mprotect __NR_mprotect
#define SYS_mq_getsetattr __NR_mq_getsetattr
#define SYS_mq_notify __NR_mq_notify
#define SYS_mq_open __NR_mq_open
#define SYS_mq_timedreceive __NR_mq_timedreceive
#define SYS_mq_timedsend __NR_mq_timedsend
#define SYS_mq_unlink __NR_mq_unlink
#define SYS_mremap __NR_mremap
#define SYS_msync __NR_msync
#define SYS_munlock __NR_munlock
#define SYS_munlockall __NR_munlockall
#define SYS_munmap __NR_munmap
#define SYS_nanosleep __NR_nanosleep
#define SYS_nfsservctl __NR_nfsservctl
#define SYS_open __NR_open
#define SYS_openat __NR_openat
#define SYS_pause __NR_pause
#define SYS_personality __NR_personality
#define SYS_pipe __NR_pipe
#define SYS_pivot_root __NR_pivot_root
#define SYS_poll __NR_poll
#define SYS_ppoll __NR_ppoll
#define SYS_prctl __NR_prctl
#define SYS_pread64 __NR_pread64
#define SYS_pselect6 __NR_pselect6
#define SYS_ptrace __NR_ptrace
#define SYS_putpmsg __NR_putpmsg
#define SYS_pwrite64 __NR_pwrite64
#define SYS_query_module __NR_query_module
#define SYS_quotactl __NR_quotactl
#define SYS_read __NR_read
#define SYS_readahead __NR_readahead
#define SYS_readlink __NR_readlink
#define SYS_readlinkat __NR_readlinkat
#define SYS_readv __NR_readv
#define SYS_reboot __NR_reboot
#define SYS_remap_file_pages __NR_remap_file_pages
#define SYS_removexattr __NR_removexattr
#define SYS_rename __NR_rename
#define SYS_renameat __NR_renameat
#define SYS_request_key __NR_request_key
#define SYS_restart_syscall __NR_restart_syscall
#define SYS_rmdir __NR_rmdir
#define SYS_rt_sigaction __NR_rt_sigaction
#define SYS_rt_sigpending __NR_rt_sigpending
#define SYS_rt_sigprocmask __NR_rt_sigprocmask
#define SYS_rt_sigqueueinfo __NR_rt_sigqueueinfo
#define SYS_rt_sigreturn __NR_rt_sigreturn
#define SYS_rt_sigsuspend __NR_rt_sigsuspend
#define SYS_rt_sigtimedwait __NR_rt_sigtimedwait
#define SYS_sched_get_priority_max __NR_sched_get_priority_max
#define SYS_sched_get_priority_min __NR_sched_get_priority_min
#define SYS_sched_getaffinity __NR_sched_getaffinity
#define SYS_sched_getparam __NR_sched_getparam
#define SYS_sched_getscheduler __NR_sched_getscheduler
#define SYS_sched_rr_get_interval __NR_sched_rr_get_interval
#define SYS_sched_setaffinity __NR_sched_setaffinity
#define SYS_sched_setparam __NR_sched_setparam
#define SYS_sched_setscheduler __NR_sched_setscheduler
#define SYS_sched_yield __NR_sched_yield
#define SYS_select __NR_select
#define SYS_sendfile __NR_sendfile
#define SYS_set_mempolicy __NR_set_mempolicy
#define SYS_set_robust_list __NR_set_robust_list
#define SYS_set_thread_area __NR_set_thread_area
#define SYS_set_tid_address __NR_set_tid_address
#define SYS_setdomainname __NR_setdomainname
#define SYS_setfsgid __NR_setfsgid
#define SYS_setfsuid __NR_setfsuid
#define SYS_setgid __NR_setgid
#define SYS_setgroups __NR_setgroups
#define SYS_sethostname __NR_sethostname
#define SYS_setitimer __NR_setitimer
#define SYS_setpgid __NR_setpgid
#define SYS_setpriority __NR_setpriority
#define SYS_setregid __NR_setregid
#define SYS_setresgid __NR_setresgid
#define SYS_setresuid __NR_setresuid
#define SYS_setreuid __NR_setreuid
#define SYS_setrlimit __NR_setrlimit
#define SYS_setsid __NR_setsid
#define SYS_settimeofday __NR_settimeofday
#define SYS_setuid __NR_setuid
#define SYS_setxattr __NR_setxattr
#define SYS_sigaltstack __NR_sigaltstack
#define SYS_splice __NR_splice
#define SYS_stat __NR_stat
#define SYS_statfs __NR_statfs
#define SYS_swapoff __NR_swapoff
#define SYS_swapon __NR_swapon
#define SYS_symlink __NR_symlink
#define SYS_symlinkat __NR_symlinkat
#define SYS_sync __NR_sync
#define SYS_sync_file_range __NR_sync_file_range
#define SYS_sysfs __NR_sysfs
#define SYS_sysinfo __NR_sysinfo
#define SYS_syslog __NR_syslog
#define SYS_tee __NR_tee
#define SYS_tgkill __NR_tgkill
#define SYS_time __NR_time
#define SYS_timer_create __NR_timer_create
#define SYS_timer_delete __NR_timer_delete
#define SYS_timer_getoverrun __NR_timer_getoverrun
#define SYS_timer_gettime __NR_timer_gettime
#define SYS_timer_settime __NR_timer_settime
#define SYS_times __NR_times
#define SYS_tkill __NR_tkill
#define SYS_truncate __NR_truncate
#define SYS_umask __NR_umask
#define SYS_umount2 __NR_umount2
#define SYS_uname __NR_uname
#define SYS_unlink __NR_unlink
#define SYS_unlinkat __NR_unlinkat
#define SYS_unshare __NR_unshare
#define SYS_uselib __NR_uselib
#define SYS_ustat __NR_ustat
#define SYS_utime __NR_utime
#define SYS_utimes __NR_utimes
#define SYS_vfork __NR_vfork
#define SYS_vhangup __NR_vhangup
#define SYS_vmsplice __NR_vmsplice
#define SYS_vserver __NR_vserver
#define SYS_wait4 __NR_wait4
#define SYS_waitid __NR_waitid
#define SYS_write __NR_write
#define SYS_writev __NR_writev
#if __WORDSIZE == 64
#define SYS_accept __NR_accept
#define SYS_arch_prctl __NR_arch_prctl
#define SYS_bind __NR_bind
#define SYS_connect __NR_connect
#define SYS_epoll_ctl_old __NR_epoll_ctl_old
#define SYS_epoll_pwait __NR_epoll_pwait
#define SYS_epoll_wait_old __NR_epoll_wait_old
#define SYS_getpeername __NR_getpeername
#define SYS_getsockname __NR_getsockname
#define SYS_getsockopt __NR_getsockopt
#define SYS_listen __NR_listen
#define SYS_msgctl __NR_msgctl
#define SYS_msgget __NR_msgget
#define SYS_msgrcv __NR_msgrcv
#define SYS_msgsnd __NR_msgsnd
#define SYS_newfstatat __NR_newfstatat
#define SYS_recvfrom __NR_recvfrom
#define SYS_recvmsg __NR_recvmsg
#define SYS_security __NR_security
#define SYS_semctl __NR_semctl
#define SYS_semget __NR_semget
#define SYS_semop __NR_semop
#define SYS_semtimedop __NR_semtimedop
#define SYS_sendmsg __NR_sendmsg
#define SYS_sendto __NR_sendto
#define SYS_setsockopt __NR_setsockopt
#define SYS_shmat __NR_shmat
#define SYS_shmctl __NR_shmctl
#define SYS_shmdt __NR_shmdt
#define SYS_shmget __NR_shmget
#define SYS_shutdown __NR_shutdown
#define SYS_signalfd __NR_signalfd
#define SYS_socket __NR_socket
#define SYS_socketpair __NR_socketpair
#define SYS_timerfd_create __NR_timerfd_create
#define SYS_tuxcall __NR_tuxcall
#define SYS_utimensat __NR_utimensat
#else
#define SYS__llseek __NR__llseek
#define SYS__newselect __NR__newselect
#define SYS_bdflush __NR_bdflush
#define SYS_break __NR_break
#define SYS_chown32 __NR_chown32
#define SYS_fadvise64_64 __NR_fadvise64_64
#define SYS_fchown32 __NR_fchown32
#define SYS_fcntl64 __NR_fcntl64
#define SYS_fstat64 __NR_fstat64
#define SYS_fstatat64 __NR_fstatat64
#define SYS_fstatfs64 __NR_fstatfs64
#define SYS_ftime __NR_ftime
#define SYS_ftruncate64 __NR_ftruncate64
#define SYS_getcpu __NR_getcpu
#define SYS_getegid32 __NR_getegid32
#define SYS_geteuid32 __NR_geteuid32
#define SYS_getgid32 __NR_getgid32
#define SYS_getgroups32 __NR_getgroups32
#define SYS_getresgid32 __NR_getresgid32
#define SYS_getresuid32 __NR_getresuid32
#define SYS_getuid32 __NR_getuid32
#define SYS_gtty __NR_gtty
#define SYS_idle __NR_idle
#define SYS_ipc __NR_ipc
#define SYS_lchown32 __NR_lchown32
#define SYS_lock __NR_lock
#define SYS_lstat64 __NR_lstat64
#define SYS_madvise1 __NR_madvise1
#define SYS_mmap2 __NR_mmap2
#define SYS_mpx __NR_mpx
#define SYS_nice __NR_nice
#define SYS_oldfstat __NR_oldfstat
#define SYS_oldlstat __NR_oldlstat
#define SYS_oldolduname __NR_oldolduname
#define SYS_oldstat __NR_oldstat
#define SYS_olduname __NR_olduname
#define SYS_prof __NR_prof
#define SYS_profil __NR_profil
#define SYS_readdir __NR_readdir
#define SYS_sendfile64 __NR_sendfile64
#define SYS_setfsgid32 __NR_setfsgid32
#define SYS_setfsuid32 __NR_setfsuid32
#define SYS_setgid32 __NR_setgid32
#define SYS_setgroups32 __NR_setgroups32
#define SYS_setregid32 __NR_setregid32
#define SYS_setresgid32 __NR_setresgid32
#define SYS_setresuid32 __NR_setresuid32
#define SYS_setreuid32 __NR_setreuid32
#define SYS_setuid32 __NR_setuid32
#define SYS_sgetmask __NR_sgetmask
#define SYS_sigaction __NR_sigaction
#define SYS_signal __NR_signal
#define SYS_sigpending __NR_sigpending
#define SYS_sigprocmask __NR_sigprocmask
#define SYS_sigreturn __NR_sigreturn
#define SYS_sigsuspend __NR_sigsuspend
#define SYS_socketcall __NR_socketcall
#define SYS_ssetmask __NR_ssetmask
#define SYS_stat64 __NR_stat64
#define SYS_statfs64 __NR_statfs64
#define SYS_stime __NR_stime
#define SYS_stty __NR_stty
#define SYS_truncate64 __NR_truncate64
#define SYS_ugetrlimit __NR_ugetrlimit
#define SYS_ulimit __NR_ulimit
#define SYS_umount __NR_umount
#define SYS_vm86 __NR_vm86
#define SYS_vm86old __NR_vm86old
#define SYS_waitpid __NR_waitpid
#endif

pthread_self


DESCRIPTION
       The pthread_self() function returns the ID of the calling thread.

pthread_equal

DESCRIPTION
       The pthread_equal() function compares two thread identifiers.

RETURN VALUE
       If  the  two  thread  IDs  are equal, pthread_equal() returns a nonzero
       value; otherwise, it returns 0.

ERRORS
       This function always succeeds.

inline void __asm_nop() {__asm__  __volatile__("nop" : : : "memory");}

inline void __asm_rep_nop() {__asm__ __volatile__("rep; nop" : : : "memory");}

 

#if defined(__i386__) || defined(__x86_64)

inline void __asm_pause() {__asm__ __volatile__("pause;");}

#elif defined(__arm64)

inline void __asm_pause() {__asm__ __volatile__("yield" : : : "memory");}

#else

inline void __asm_pause() {__asm_nop();}

#endif

https://blog.csdn.net/wangbinyantai/article/details/78984461

gcc内嵌汇编简介
在内嵌汇编中,可以将C语言表达式指定为汇编指令的操作数,而且不用去管如何将C语言表达式的值读入哪个寄存器,以及如何将计算结果写回C 变量,你只要告诉程序中C语言表达式与汇编指令操作数之间的对应关系即可, GCC会自动插入代码完成必要的操作。

1、简单的内嵌汇编
例:

__asm__ __volatile__("hlt"); "__asm__"表示后面的代码为内嵌汇编,"asm"是"__asm__"的别名。"__volatile__"表示编译器不要优化代码,后面的指令保留原样,"volatile"是它的别名。括号里面是汇编指令。

2、内嵌汇编举例

使用内嵌汇编,要先编写汇编指令模板,然后将C语言表达式与指令的操作数相关联,并告诉GCC对这些操作有哪些限制条件。例如在下面的汇编语句:
__asm__ __violate__ ("movl %1,%0" : "=r" (result) : "m" (input));

"movl %1,%0"是指令模板;"%0"和"%1"代表指令的操作数,称为占位符,内嵌汇编靠它们将C 语言表达式与指令操作数相对应。指令模板后面用小括号括起来的是C语言表达式,本例中只有两个:"result"和"input",他们按照出现的顺序分别与指令操作数"%0","%1"对应;注意对应顺序:第一个C 表达式对应"%0";第二个表达式对应"%1",依次类推,操作数至多有10 个,分别用"%0","%1"...."%9"表示。在每个操作数前面有一个用引号括起来的字符串,字符串的内容是对该操作数的限制或者说要求。"result"前面的限制字符串是"=r",其中"="表示"result"是输出操作数,"r"表示需要将"result"与某个通用寄存器相关联,先将操作数的值读入寄存器,然后在指令中使用相应寄存器,而不是"result"本身,当然指令执行完后需要将寄存器中的值存入变量"result",从表面上看好像是指令直接对"result"进行操作,实际上GCC做了隐式处理,这样我们可以少写一些指令。"input"前面的"r"表示该表达式需要先放入某个寄存器,然后在指令中使用该寄存器参加运算。
C 表达式或者变量与寄存器的关系由GCC自动处理,我们只需使用限制字符串指导GCC如何处理即可。限制字符必须与指令对操作数的要求相匹配,否则产生的汇编代码将会有错,读者可以将上例中的两个"r",都改为"m"(m表示操作数放在内存,而不是寄存器中),编译后得到的结果是:
movl input, result
很明显这是一条非法指令,因此限制字符串必须与指令对操作数的要求匹配。例如指令movl允许寄存器到寄存器,立即数到寄存器等,但是不允许内存到内存的操作,因此两个操作数不能同时使用"m"作为限定字符。



内嵌汇编语法如下:
__asm__(汇编语句模板: 输出部分: 输入部分: 破坏描述部分)
共四个部分:汇编语句模板,输出部分,输入部分,破坏描述部分,各部分使用":"格开,汇编语句模板必不可少,其他三部分可选,如果使用了后面的部分,而前面部分为空,也需要用":"格开,相应部分内容为空。例如:
__asm__ __volatile__("cli": : :"memory")

If our assembly statement must execute where we put it, (i.e. must not be moved out of a loop as an optimization), put the keyword volatile after asm and before the ()’s. So to keep it from moving, deleting and all.

1、汇编语句模板
汇编语句模板由汇编语句序列组成,语句之间使用";"、"/n"或"/n/t"分开。指令中的操作数可以使用占位符引用C语言变量,操作数占位符最多10 个,名称如下:%0,%1,...,%9。指令中使用占位符表示的操作数,总被视为long型(4个字节),但对其施加的操作根据指令可以是字或者字节,当把操作数当作字或者字节使用时,默认为低字或者低字节。对字节操作可以显式的指明是低字节还是次字节。方法是在%和序号之间插入一个字母,"b"代表低字节,"h"代表高字节,例如:%h1。

2、输出部分
输出部分描述输出操作数,不同的操作数描述符之间用逗号格开,每个操作数描述符由限定字符串和C 语言变量组成。每个输出操作数的限定字符串必须包含"="表示他是一个输出操作数。
例:
__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x) )
描述符字符串表示对该变量的限制条件,这样GCC 就可以根据这些条件决定如何分配寄存器,如何产生必要的代码处理指令操作数与C表达式或C变量之间的联系。
3、输入部分
输入部分描述输入操作数,不同的操作数描述符之间使用逗号格开,每个操作数描述符由限定字符串和C语言表达式或者C语言变量组成。
例1 :
__asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt));
例二(bitops.h):
Static __inline__ void __set_bit(int nr, volatile void * addr)
{
__asm__(
"btsl %1,%0"
:"=m" (ADDR)
:"Ir" (nr));
}

后例功能是将(*addr)的第nr位设为1。第一个占位符%0与C 语言变量ADDR对应,第二个占位符%1与C语言变量nr对应。因此上面的汇编语句代码与下面的伪代码等价:btsl nr, ADDR,该指令的两个操作数不能全是内存变量,因此将nr的限定字符串指定为"Ir",将nr 与立即数或者寄存器相关联,这样两个操作数中只有ADDR为内存变量。
4、限制字符
4.1、限制字符列表
限制字符有很多种,有些是与特定体系结构相关,此处仅列出常用的限定字符和i386中可能用到的一些常用的限定符。它们的作用是指示编译器如何处理其后的C语言变量与指令操作数之间的关系。

分类 限定符 描述
通用寄存器 "a" 将输入变量放入eax
这里有一个问题:假设eax已经被使用,那怎么办?
其实很简单:因为GCC 知道eax 已经被使用,它在这段汇编代码
的起始处插入一条语句pushl %eax,将eax 内容保存到堆栈,然
后在这段代码结束处再增加一条语句popl %eax,恢复eax的内容
"b" 将输入变量放入ebx
"c" 将输入变量放入ecx
"d" 将输入变量放入edx
"s" 将输入变量放入esi
"d" 将输入变量放入edi
"q" 将输入变量放入eax,ebx,ecx,edx中的一个
"r" 将输入变量放入通用寄存器,也就是eax,ebx,ecx,
edx,esi,edi中的一个
"A" 把eax和edx合成一个64 位的寄存器(use long longs)

内存 "m" 内存变量
"o" 操作数为内存变量,但是其寻址方式是偏移量类型,
也即是基址寻址,或者是基址加变址寻址
"V" 操作数为内存变量,但寻址方式不是偏移量类型
" " 操作数为内存变量,但寻址方式为自动增量
"p" 操作数是一个合法的内存地址(指针)

寄存器或内存 "g" 将输入变量放入eax,ebx,ecx,edx中的一个
或者作为内存变量
"X" 操作数可以是任何类型

立即数
"I" 0-31之间的立即数(用于32位移位指令)
"J" 0-63之间的立即数(用于64位移位指令)
"N" 0-255之间的立即数(用于out指令)
"i" 立即数
"n" 立即数,有些系统不支持除字以外的立即数,
这些系统应该使用"n"而不是"i"

匹配 " 0 ", 表示用它限制的操作数与某个指定的操作数匹配,
"1" ... 也即该操作数就是指定的那个操作数,例如"0"
"9" 去描述"%1"操作数,那么"%1"引用的其实就
是"%0"操作数,注意作为限定符字母的0-9 与
指令中的"%0"-"%9"的区别,前者描述操作数,
后者代表操作数。
& 该输出操作数不能使用过和输入操作数相同的寄存器

操作数类型 "=" 操作数在指令中是只写的(输出操作数)
"+" 操作数在指令中是读写类型的(输入输出操作数)

浮点数 "f" 浮点寄存器
"t" 第一个浮点寄存器
"u" 第二个浮点寄存器
"G" 标准的80387浮点常数
% 该操作数可以和下一个操作数交换位置
例如addl的两个操作数可以交换顺序
(当然两个操作数都不能是立即数)
# 部分注释,从该字符到其后的逗号之间所有字母被忽略
* 表示如果选用寄存器,则其后的字母被忽略

5、破坏描述部分
破坏描述符用于通知编译器我们使用了哪些寄存器或内存,由逗号格开的字符串组成,每个字符串描述一种情况,一般是寄存器名;除寄存器外还有"memory"。例如:"%eax","%ebx","memory"等。

"memory"比较特殊,可能是内嵌汇编中最难懂部分。为解释清楚它,先介绍一下编译器的优化知识,再看C关键字volatile。最后去看该描述符。

1、编译器优化介绍
内存访问速度远不及CPU处理速度,为提高机器整体性能,在硬件上引入硬件高速缓存Cache,加速对内存的访问。另外在现代CPU中指令的执行并不一定严格按照顺序执行,没有相关性的指令可以乱序执行,以充分利用CPU的指令流水线,提高执行速度。以上是硬件级别的优化。再看软件一级的优化:一种是在编写代码时由程序员优化,另一种是由编译器进行优化。编译器优化常用的方法有:将内存变量缓存到寄存器;调整指令顺序充分利用CPU指令流水线,常见的是重新排序读写指令。对常规内存进行优化的时候,这些优化是透明的,而且效率很好。由编译器优化或者硬件重新排序引起的问题的解决办法是在从硬件(或者其他处理器)的角度看必须以特定顺序执行的操作之间设置内存屏障(memory barrier),linux 提供了一个宏解决编译器的执行顺序问题。
void Barrier(void)
这个函数通知编译器插入一个内存屏障,但对硬件无效,编译后的代码会把当前CPU寄存器中的所有修改过的数值存入内存,需要这些数据的时候再重新从内存中读出。

2、C语言关键字volatile
C 语言关键字volatile(注意它是用来修饰变量而不是上面介绍的__volatile__)表明某个变量的值可能在外部被改变,因此对这些变量的存取不能缓存到寄存器,每次使用时需要重新存取。该关键字在多线程环境下经常使用,因为在编写多线程的程序时,同一个变量可能被多个线程修改,而程序通过该变量同步各个线程,例如:
DWORD __stdcall threadFunc(LPVOID signal)
{
int* intSignal=reinterpret_cast(signal);
*intSignal=2;
while(*intSignal!=1)
sleep(1000);
return 0;
}
该线程启动时将intSignal 置为2,然后循环等待直到intSignal 为1 时退出。显然intSignal的值必须在外部被改变,否则该线程不会退出。但是实际运行的时候该线程却不会退出,即使在外部将它的值改为1,看一下对应的伪汇编代码就明白了:
mov ax,signal
label:
if(ax!=1)
goto label

对于C编译器来说,它并不知道这个值会被其他线程修改。自然就把它cache在寄存器里面。记住,C 编译器是没有线程概念的!这时候就需要用到volatile。volatile 的本意是指:这个值可能会在当前线程外部被改变。也就是说,我们要在threadFunc中的intSignal前面加上volatile关键字,这时候,编译器知道该变量的值会在外部改变,因此每次访问该变量时会重新读取,所作的循环变为如下面伪码所示:
label:
mov ax,signal
if(ax!=1)
goto label

3、Memory
有了上面的知识就不难理解Memory修改描述符了,Memory描述符告知GCC:
1)不要将该段内嵌汇编指令与前面的指令重新排序;也就是在执行内嵌汇编代码之前,它前面的指令都执行完毕
2)不要将变量缓存到寄存器,因为这段代码可能会用到内存变量,而这些内存变量会以不可预知的方式发生改变,因此GCC插入必要的代码先将缓存到寄存器的变量值写回内存,如果后面又访问这些变量,需要重新访问内存。

如果汇编指令修改了内存,但是GCC 本身却察觉不到,因为在输出部分没有描述,此时就需要在修改描述部分增加"memory",告诉GCC 内存已经被修改,GCC 得知这个信息后,就会在这段指令之前,插入必要的指令将前面因为优化Cache 到寄存器中的变量值先写回内存,如果以后又要使用这些变量再重新读取。

使用"volatile"也可以达到这个目的,但是我们在每个变量前增加该关键字,不如使用"memory"方便

https://blog.csdn.net/wangbinyantai/article/details/78984461

 

 

sched_yield

DESCRIPTION
       sched_yield()  causes  the  calling  thread to relinquish the CPU.  The
       thread is moved to the end of the queue for its static priority  and  a
       new thread gets to run.

RETURN VALUE
       On  success,  sched_yield()  returns  0.  On error, -1 is returned, and
       errno is set appropriately.

ERRORS
       In the Linux implementation, sched_yield() always succeeds.

 

fstat/lstat/stat区别

stat系统调用系列包括了fstat、stat和lstat,它们都是用来返回“相关文件状态信息”的,三者的不同之处在于设定源文件的方式不同。

1

首先隆重介绍的是一个非常重要的”VIP”人物,他是fstat, stat和lstat三者都要用到的一个结构体类型,名字叫做struct stat。可以说,没有这个struct stat的支持,上述三个系统调用将寸步难行。

 

这个struct stat结构体在不同的UNIX/Linux系统中的定义是有小的区别的,但你完全不用担心,这并不会影响我们的使用。

在struct stat结构体中我们常用的且各个平台都一定有的域是:

st_mode 文件权限和文件类型信息 (记住这个黑体橘红色)

st_ino   与该文件关联的inode

st_dev   保存文件的设备

st_uid   文件属主的UID号

st_gid   文件属主的GID号

st_atime 文件上一次被访问的时间

st_ctime 文件的权限、属主、组或内容上一次被修改的时间

st_mtime 文件的内容上一次被修改的时间。(和st_ctime的不同之处显而易见)

st_nlink  该文件上硬连接的个数

我分别提取了solaris(UNIX)和fedora(Linux)的struct stat结构体的原始定义:大家可以自己比对一下便可以发现两者确实有所不同,但主要的域是完全相同的。

solaris的struct stat定义:

struct stat { dev_t           st_dev; ino_t           st_ino; mode_t          st_mode; nlink_t         st_nlink; uid_t           st_uid; gid_t           st_gid; dev_t           st_rdev; off_t           st_size; timestruc_t     st_atim; timestruc_t     st_mtim; timestruc_t     st_ctim; blksize_t       st_blksize; blkcnt_t        st_blocks; char            st_fstype[_ST_FSTYPSZ]; };

fedora的struct stat定义:

struct stat { __dev_t st_dev;                     /* Device.  */ unsigned short int __pad1; __ino_t st_ino;                     /* File serial number.  */ __mode_t st_mode;                   /* File mode.  */ __nlink_t st_nlink;                 /* Link count.  */ __uid_t st_uid;                     /* User ID of the file’s owner. */ __gid_t st_gid;                     /* Group ID of the file’s group.*/ __dev_t st_rdev;                    /* Device number, if device.  */ unsigned short int __pad2; __off_t st_size;                    /* Size of file, in bytes.  */ __blksize_t st_blksize;             /* Optimal block size for I/O.  */ __blkcnt_t st_blocks;               /* Number 512-byte blocks allocated. */ struct timespec st_atim;            /* Time of last access.  */ struct timespec st_mtim;            /* Time of last modification.  */ struct timespec st_ctim;            /* Time of last status change.  */ unsigned long int __unused4; unsigned long int __unused5; };

2

大家一定注意到了,在上面列举域的时候,我在st_mode处使用了黑体橘红色标识,原因在于这个域不像其他域那么容易使用,其他的域的值显而易见,而st_mode域是需要一些宏予以配合才能使用的。其实,通俗说,这些宏就是一些特定位置为1的二进制数的外号,我们使用它们和st_mode进行”&”操作,从而就可以得到某些特定的信息。
文件类型标志包括:

S_IFBLK:文件是一个特殊的块设备

S_IFDIR:文件是一个目录

S_IFCHR:文件是一个特殊的字符设备

S_IFIFO:文件是一个FIFO设备

S_IFREG:文件是一个普通文件(REG即使regular啦)

S_IFLNK:文件是一个符号链接

其他模式标志包括:

S_ISUID:文件设置了SUID位

S_ISGID:文件设置了SGID位

S_ISVTX:文件设置了sticky位

用于解释st_mode标志的掩码包括:

S_IFMT:文件类型

S_IRWXU:属主的读/写/执行权限,可以分成S_IXUSR, S_IRUSR, S_IWUSR

S_IRWXG:属组的读/写/执行权限,可以分成S_IXGRP, S_IRGRP, S_IWGRP

S_IRWXO:其他用户的读/写/执行权限,可以分为S_IXOTH, S_IROTH, S_IWOTH

还有一些用于帮助确定文件类型的宏定义,这些和上面的宏不一样,这些是带有参数的宏,类似与函数的使用方法:

S_ISBLK:测试是否是特殊的块设备文件

S_ISCHR:测试是否是特殊的字符设备文件

S_ISDIR:测试是否是目录(我估计find . -type d的源代码实现中就用到了这个宏)

S_ISFIFO:测试是否是FIFO设备

S_ISREG:测试是否是普通文件

S_ISLNK:测试是否是符号链接

S_ISSOCK:测试是否是socket
3

我们已经学习完了struct stat和各种st_mode相关宏,现在就可以拿它们和stat系统调用相互配合工作了!

int fstat(int filedes, struct stat *buf);

int stat(const char *path, struct stat *buf);

int lstat(const char *path, struct stat *buf);

聪明人一眼就能看出来fstat的第一个参数是和另外两个不一样的,对!fstat区别于另外两个系统调用的地方在于,fstat系统调用接受的是 一个“文件描述符”,而另外两个则直接接受“文件全路径”。文件描述符是需要我们用open系统调用后才能得到的,而文件全路经直接写就可以了。

stat和lstat的区别:当文件是一个符号链接时,lstat返回的是该符号链接本身的信息;而stat返回的是该链接指向的文件的信息。(似乎有些晕吧,这样记,lstat比stat多了一个l,因此它是有本事处理符号链接文件的,因此当遇到符号链接文件时,lstat当然不会放过。而 stat系统调用没有这个本事,它只能对符号链接文件睁一只眼闭一只眼,直接去处理链接所指文件喽)
转自:https://www.cnblogs.com/aizaifengyu/archive/2013/02/04/2891493.html

 

read/pread/readv/write/pwrite/writev/lseek

https://blog.csdn.net/zongcai249/article/details/17598411


1.       文件I/O相关(进程->fd->文件)(文件fd, buf):

(1)       read()

形式:#include<unistd.h>

      ssize_t  read (int filedes,  void *buf,  size_t  nbytes );

      成功:返回读到的字节数;出错:返回-1;文件尾:返回0;

原因:基本系统调用功能;

实现:文件(由filedes所指)-读nbytes字节->内存buf中。

补充:有多种情况可使实际读到的字节数少于要求读的字节数:

当从普通文件读时,在读到要求字节数之前已到达了文件尾端。

当从终端设备读时,通常一次最多读一行。

当从网络读时,网络中缓冲机构可能造成返回值小于所要求读的字节数。

当从管道或FIFO读时,如若管道包含的字节少于所需的数量,那么只返回实际用

的字节数。

当从某些面向记录的设备读时,一次最多返回一个记录。

当某一信号造成中断,而已经读了部分数据量时。

读操作从文件的当前偏移量处开始,在成功返回之前,该偏移量将增加实际读到的字节数。常用的unix系统shell都提供一种方法,它在标准输入上打开一个文件,在标准输出上追寻或重写一个文件,这使得程序不必自行打开输入和输出文件。

(2)       write()

形式:#include<unistd.h>

      ssize_t  write (int filedes,  const void *buf,  size_t  nbytes );

      成功:返回已写的字节数;出错:返回-1;

原因:基本系统调用功能;

实现:文件(由filedes所指)<-写nbytes字节-内存buf中。

补充:write出错的一个常见的原因是:磁盘已写满,或者超过了一个给定进程的文件长度限制。对于普通文件,写操作从文件的当前偏移量处开始。如果在打开该文件时,指定了O_APPEND选项,则在每次写操作之前,将文件偏移量设置在文件的当前结尾处。在一次成功写之后,该文件偏移量增加实际写的字节数。

(3)       pread()

形式:#include<unistd.h>

      ssize_t  pread (int filedes,   void *buf,  size_t  nbytes,  off_t  offset );

  成功:返回读到的字节数;出错:返回-1;到文件结尾:返回0

原因:由于lseek和read 调用之间,内核可能会临时挂起进程,所以对同步问题造成了问题,调用pread相当于顺序调用了lseek 和 read,这两个操作相当于一个捆绑的原子操作。

实现:文件(由filedes所指)-读nbytes字节->内存buf中。

补充:调用pread时,无法中断其定位和读操作,另外不更新文件指针。

(4)       pwrite()

形式:#include<unistd.h>

      ssize_t  pwrite (int filedes,   const void *buf,  size_t  nbytes,  off_t  offset );

  成功:返回已写的字节数;出错:返回-1;

原因:由于lseek和write 调用之间,内核可能会临时挂起进程,所以对同步问题造成了问题,调用pwrite相当于顺序调用了lseek 和 write,这两个操作相当于一个捆绑的原子操作。

实现:文件(由filedes所指)<-写nbytes字节-内存buf中。

补充:调用pwrite时,无法中断其定位和读操作,另外不更新文件指针。

 

2.       流(stream)或标准I/O( 进程->fp->流(FILE+缓冲)->文件)(内存buf, 流fp):

每次输入一个字符:

(1)       getc();

格式:#include <stdio.h>

      int getc(FILE *fp);

      成功:返回下一个字符;出错:返回EOF;文件尾:EOF;

实现:内存 <-读一个字符c- 流(由fp所指的流,是文件的逻辑代表)

原因:在标准I/O中用,将流看成文件的逻辑代表,将对进程->文件的操作,现转换为进程->流(也就是相当于文件)的操作。

补充:函数在返回下一个字符时,会将其unsigned char类型转换为int类型。为不带符号的理由是,如果最高位是1也不会使返回值为负。要求整形返回值的理由是,这样就可以返回所有可能的字符值再加上一个已出错或已到达文件尾端的指示值。即字符值变为正的int值,负的值就是出错或是到达文件尾端。(负值表特殊意义),同时不论是出错还是到达文件尾端,这三个函数都返回同样的值即都是-1。由于每个流在FILE对象中维持了两个标志,即出错标志和文件结束标志,为了区分其不同,必须调用ferror或feof。

(2)       fgetc();

格式:#include <stdio.h>

      int fgetc(FILE *fp);

      成功:返回下一个字符;出错:返回EOF;文件尾:EOF;

 

实现:同getc

原因:同getc

补充:同getc

(3)       getchar();

格式:#include <stdio.h>

      int getchar(void);

成功:返回下一个字符;出错:返回EOF;文件尾:EOF;

实现:内存 <-读一个字符c- 流(由stdin所指的流,是标准输入文件的逻辑代表),所以getchar=getc(stdin);

原因:同getc

补充:同getc

 

每次输入一行:

(4)       fgets();

格式:#include <stdio.h>

      char *fgets(char *restrict buf,  Int n,  FILE *restrict  fp);

      成功:返回buf;出错:返回NULL; 文件结尾:NULL;

实现:内存buf <-从fp所指的流中取一行字符- 流(由fp所指)

原因:在标准I/O中用,将流看成文件的逻辑代表,将对进程->文件的操作,现转换为进程->流(也就是相当于文件)的操作。

补充:必须指定用户进程缓冲区的长度n,即buf的大小,此函数从流中一直读到下一个换行符为止,但是不超过n-1个字符,读入的字符被送入用户缓冲区buf中。该缓冲区以null字符结尾。如若该行包括最后换行符的字数大于n-1,则其只返回一个不完整的行,但是缓冲区buf总是以null字符结尾,对此函数的调用会继续读该行。缓冲区buf中的内容为:(字符+换行符)+null。所以字符+换行符<=n-1,因为一定要留一个NULL字符来标识缓冲区的结束;

(5)       gets();

格式:#include <stdio.h>

      char *gets(char * buf);

      成功:返回buf;出错:返回NULL; 文件结尾:NULL;

实现:内存buf <-从stdin所指的流中取1行字符-标准输入流(由fp=stdin所指)

原因:同上;

补充:不推荐使用,问题是调用者在使用gets时,不能指定缓冲区buf(用户进程)的长度,这样可能造成缓冲区溢出。

 

每次输出一个字符:

(6)       putc();

格式:#include <stdio.h>

      int putc(int c ,FILE *fp);

      成功:返回c;出错:返回EOF;

实现:内存中整形变量c-写字符C->流(由fp所指)。至于流什么时候将C写入文件中,这个由库函数来实现,不用用户操心;

原因:

补充:

 

(7)       fputc();

格式:#include <stdio.h>

      int fputc(int c ,FILE *fp);

      成功:返回c;出错:返回EOF;

实现:内存中整形变量c-写字符C->流(由fp所指)。至于流什么时候将C写入文件中,这个由库函数来实现,不用用户操心;

原因:

补充:

 

(8)       putchar();

格式:#include <stdio.h>

      int putchar(int c);

      成功:返回c;出错:返回EOF;

实现:内存中整形变量c-写字符C->流(由fp=stdout所指)。至于流什么时候将C写入标准输出文件中,这个由库函数来实现,不用用户操心;

原因:

补充:putchar(c)=putc(c,stdout);

 

每次输出一行:

(9)       fputs();

格式:#include <stdio.h>

      int fputs(const char *restrict  str, FILE  *restrict  fp);

   成功:返回非负值;出错:返回EOF;

实现:内存中字符数组str-写字符数组str->流(由fp所指)。

原因:

补充:将一个以null符终止的字符串(相当于用户空间buf,肯定有null,对应于fgets的buf中一定要有个null来标识缓冲区buf的结束。)写到指定的流,尾端的终止符null不写进流中。注意,这并不一定是每次输出一行,因为它并不要求在null之前一定是换行符,buf中有就有,没有就没有,通常,在空字符之前是一个换行符,但并不要求总是如此。用户空间buf:字符(+换行符)+null;流中的buf:字符+换行符。

 

(10)   puts();

格式:#include <stdio.h>

      int puts(const char * str);

   成功:返回非负值;出错:返回EOF;

实现:内存中字符数组str-写字符数组str->标准输出流(由fp=stdout所指)。

原因:

补充:将一个以null结尾的字符串写到标准输出上,相当于进程->流->标准输出文件。终止符不写出,但是puts然后又将一个换行符写到标准输出。应当少用,以免需要记住它在最后是否添加了一个换行符。而fgets和fputs在处理换行符,本着实事求是的态度,有就有,没有就没有,不会在用户buf和流缓冲以及文件中自己添加,只是在数据经过流缓冲时,增加或是过滤到null字符。当fgets时会在用户buf中增加一个null以标识用户buf的结束,而fputs时,以null为终止字符,但是尾端的null并不写在流中。

 

二进制I/O:

(11)   fread()

格式:#include <stdio.h>

      ssize_t  fread(void *restrict ptr, size_t size, size_t nobj, FILE *restrict  fp);

      成功:读到的对象数。

实现:内存始址ptr<-读N个对象- 流(由fp所指)

原因:以上有一次一个字符或是一次一行的方式进行I/O操作,当我们读或写一个结构时,对于一次一个字符的方式,必须循环通过整个结构,每次循环处理一个字节,一次读或写一个字节,这会很烦。而对于一次一行的方式,当每次结构体中有null字符时,fputs就会停止,所以也不能用它实现读结构,同时fgets中包含有null字节或换行符,其也不能正常工作。所以要并实现结构体作为一个整体的读或写。

补充:使用二进制的基本问题是:它只能用于读在同一系统上已写的数据。其原

因是:在结构中,同一成员偏移量可能因为编译器和系统而异,另外,用来存储多字节整数和浮点值的二进制格式在不同的机器体系结构之间也可能不同。

 

 

(12)   fwrite()

格式:#include <stdio.h>

      ssize_t  fwrite(const void *restrict ptr, size_t size, size_t nobj, FILE *restrict  fp);

      成功:写的对象数。

 

实现:内存始址ptr-写N个对象-> 流(由fp所指)

原因:

补充:

 

格式化输入:文件-流->格式转换->内存变量中

(13)   scanf();

格式:#include <stdio.h>

      int scanf(const char *restrict format,…)

   成功:指定的输入项数;出错:返回EOF;输入出错或在任意变换前已到达文件结尾:EOF;

实现:标准输入流->格式转换->内存变量中。用于分析输入字符串,并将字符序列转换成指定类型的变量。格式之后的各个参数包含了变量的地址,以用转换结果初始化这些变量。

原因:要在流中做格式转换,再将结果放到内存变量中

补充:

 

(14)   fscanf();

格式:#include <stdio.h>

      int fscanf(FILE *restrict fp, const char *restrict format,…)

   成功:指定的输入项数;出错:返回EOF;输入出错或在任意变换前已到达文件结尾:EOF;

实现:输入流->格式转换->内存变量中

原因:

补充:

 

(15)   sscanf();

格式:#include <stdio.h>

      int sscanf(const char *restrict buf, const char *restrict format,…)

   成功:指定的输入项数;出错:返回EOF;输入出错或在任意变换前已到达文件结尾:EOF;

实现:内存buf->格式转换->内存变量中。

原因:

补充:对于scanf(), 从标准输入流中输入;fscanf,从流中输入; sscanf,这个比较特殊,不是从流中输入,而是内存的一个buf相当于string中输入。

 

(16)   vscanf();

格式:#include <stdio.h>

      int vscanf(const char *restrict format, va_list  arg);

   成功:指定的输入项数;出错:返回EOF;输入出错或在任意变换前已到达文件结尾:EOF;

实现:标准输入流->格式转换->内存变量中。用于分析输入字符串,并将字符序列转换成指定类型的变量。格式之后的各个参数包含了变量的地址,以用转换结果初始化这些变量。同于scanf,只是将原来的可变参数…换成了arg;

原因:要在流中做格式转换,再将结果放到内存变量中

补充:

 

(17)   vfscanf();

格式:#include <stdio.h>

      int vfscanf(FILE *restrict fp, const char *restrict format, va_list  arg)

   成功:指定的输入项数;出错:返回EOF;输入出错或在任意变换前已到达文件结尾:EOF;

实现:输入流->格式转换->内存变量中, 同于fscanf,只是将原来的可变参数…,换成了arg;

原因:

补充:

 

(18)   vsscanf();

格式:#include <stdio.h>

      int vsscanf(const char *restrict buf, const char *restrict format, va_list  arg)

   成功:指定的输入项数;出错:返回EOF;输入出错或在任意变换前已到达文件结尾:EOF;

实现:内存buf->格式转换->内存变量中。同于sscanf,只是将原来的可变参数…,换成了arg;

原因:

补充:对于scanf(), 从标准输入流中输入;fscanf,从流中输入; sscanf,这个比较特殊,不是从流中输入,而是内存的一个buf相当于string中输入。

 

 

格式化输出:文件-流<-格式字符串<-内存变量

(19)   printf();

格式:#include <stdio.h>

      int  printf(const char *restrict format, …);

      成功:返回输出字符数;出错:返回负值;

实现:标准输出流<-格式字符串<-内存变量

原因:要将内存变量的数据做格式变换,再将变换的结果放入流中

补充:

 

(20)   fprintf();

格式:#include <stdio.h>

      int  fprintf(FILE *restrict fp,const char *restrict format, …);

      成功:返回输出字符数;出错:返回负值;

实现:文件-输出流<-格式字符串<-内存变量

原因:

补充:

 

(21)   sprint();

格式:#include <stdio.h>

      int  sprintf(char *restrict buf, const char *restrict format, …);

      成功:返回输出字符数;出错:返回负值;

实现:内存字符串buf<-格式字符串<-内存变量,就是将格式化的字符串送入数组buf而不是指定的流中。在数组的尾端自动加一个null字节,但该字节不包括在返回值中。

原因:

补充:

 

(22)   snprintf();

格式:#include <stdio.h>

      int  snprintf(char *restrict buf, size_t n , const char *restrict format, …);

      成功:返回输出字符数;出错:返回负值;

实现:内存字符串buf<-格式字符串<-内存变量,就是将格式化的字符串送入数组buf而不是指定的流中。在数组的尾端自动加一个null字节,但该字节不包括在返回值中。只能输入n-1个字符,超过的任何字条都会被丢弃。

原因:

补充:

 

(23)   vprintf();

格式:#include <stdarg.h>

      #include <stdio.h>

      int  vprintf(const char *restrict format, va_list  arg);

      成功:返回输出字符数;出错:返回负值;

实现:标准输出流<-格式字符串<-内存变量,同于printf,只是将原来的可变参数…换成了arg;

原因:要将内存变量的数据做格式变换,再将变换的结果放入流中

补充:

 

(24)   vfprintf();

格式:#include <stdarg.h>

      #include <stdio.h>

      int  vfprintf(FILE *restrict fp,const char *restrict format, va_list  arg);

      成功:返回输出字符数;出错:返回负值;

实现:输出流<-格式字符串<-内存变量,同于fprintf,只是将原来的可变参数…换成了arg;

原因:要将内存变量的数据做格式变换,再将变换的结果放入流中

补充:

(25)   vsprintf();

格式:#include <stdarg.h>

      #include <stdio.h>

      int  vsprintf(char *restrict buf, const char *restrict format, va_list  arg);

      成功:返回输出字符数;出错:返回负值;

实现:内存数组buf<-格式字符串<-内存变量,同于sprintf,只是将原来的可变参数…换成了arg; 就是将格式化的字符串送入数组buf而不是指定的流中。在数组的尾端自动加一个null字节,但该字节不包括在返回值中。

原因:要将内存变量的数据做格式变换,再将变换的结果放入流中

补充:

 

(26)   vsnprintf();

格式:#include <stdio.h>

      int  vsnprintf(char *restrict buf, size_t n , const char *restrict format, va_list arg);

      成功:返回输出字符数;出错:返回负值;

实现:内存字符串buf<-格式字符串<-内存变量, 同于snprintf,只是将原来的可变参数…换成了arg; 就是将格式化的字符串送入数组buf而不是指定的流中。在数组的尾端自动加一个null字节,但该字节不包括在返回值中。只能输入n-1个字符,超过的任何字条都会被丢弃。

原因:

补充:

 

3.       高级I/O:(文件(fd), 内存buf )

(1)       readv()

格式:#include <sys/uio.h>

      ssize_t  readv(int filedes, const  struct iovec *iov, int iovcnt);

      成功:返回已读的字节数;出错:返回-1;

实现:文件(fd)->内存向量中

原因:在一次函数调用中读、写多个非连续缓冲区,但是这些缓冲区已经用iovec表示好了。减少了系统调用的次数。

补充:

(2)       writev()

格式:#include <sys/uio.h>

      ssize_t  writev(int filedes, const  struct iovec *iov, int iovcnt);

      成功:返回已读的字节数;出错:返回-1;

实现:文件(fd)<-内存向量

原因:在一次函数调用中读、写多个非连续缓冲区,但是这些缓冲区已经用iovec表示好了。减少了系统调用的次数。

补充:

 

(3)       readn()

格式:#include <sys/uio.h>

      ssize_t  readn(int filedes, void *bug, size_t  nbytes);

      成功:返回已读的字节数;出错:返回-1;

实现:文件(fd)->内存buf中

原因:管道、FIFO以及某些设备,特别是终端、网络和STREAMS设备有下列两种性质:一是,一次read操作所返回的数据可能少于所要求的数据,即使还没达到文件尾端也可能是这样的。这不是一个错误,应当继续读该设备。二是,一次write操作所返回的值也可能少于所指定输出的字节数,这可能是由若干因素造成的。这些也不是错误,也应当继续写余下的数据至该设备。通常只对非阻塞描述符,或捕捉到一个信号时,才发生这种write的中途返回。但是在读写磁盘时,很少遇到这样的情况。所以这个函数其实是按需要多次调用read 和write直至读、写了N个字节数据,即我们称之为:直到集齐了再返回。

补充:

 

(4)       written()

格式:#include <sys/uio.h>

      ssize_t  writen(int filedes, void *bug, size_t  nbytes);

      成功:返回已读的字节数;出错:返回-1;

实现:文件(fd)<-内存buf中

原因:管道、FIFO以及某些设备,特别是终端、网络和STREAMS设备有下列两种性质:一是,一次read操作所返回的数据可能少于所要求的数据,即使还没达到文件尾端也可能是这样的。这不是一个错误,应当继续读该设备。二是,一次write操作所返回的值也可能少于所指定输出的字节数,这可能是由若干因素造成的。这些也不是错误,也应当继续写余下的数据至该设备。通常只对非阻塞描述符,或捕捉到一个信号时,才发生这种write的中途返回。但是在读写磁盘时,很少遇到这样的情况。所以这个函数其实是按需要多次调用read 和write直至读、写了N个字节数据,即我们称之为:直到集齐了再返回。

补充:

4.       IPC中:

消息队列中:

(1)       msgrcv()

格式:#include <sys/msg.h>

      ssize_t  msgrcv(int  msqid, void *ptr, size_t nbytes, long type, int flag);

      成功:返回消息的数据部分长度;出错:-1;

实现:消息队列->内存消息结构体(由ptr指向)

原因:

补充:nbytes说明数据缓冲区的长度。用来构造mymesg。若返回的消息大于nbytes,而且在flag中设置了MSG_NOERROR,则该消息被截短。如果没有设置这一标志,而消息又太长,则出错返回E2BIG(消息仍留在队列中。参数type我们可以指定想要哪一种消息。可以指定flag值为IPC_NOWAIT,使操作不阻塞。这使得如果没有所指定类型的消息,则msgrcv返回-1,errno设置为ENOMSG。

 

(2)       msgsnd()

格式:#include <sys/msg.h>

      int  msgsnd(int  msqid, const void *ptr, size_t nbytes, long type, int flag);

      成功:返回0;出错:-1;

实现:消息队列<-内存消息结构体(由ptr指向)

原因:

补充:每个消息都由三部分组成,它们是:正长整型类型字段、实际数据字节(这两个对就myseq结构体)、非负长度(nbytes)。消息总是放在队列尾端。ptr参数指向一个长整型数,它包含了正的整型消息类型,在其后紧跟着消息数据。可以定义如下结构:struct myseq{ long mtype; char mtex[512];}  于是ptr就是一个指向mymesg结构的指针。接收者可以用消息类型以非先进先出的次序取消息。

 

 

 

 

SOCKET中:

(1)       revc()

格式:#include <sys/socket.h>

      ssize_t  recv(int sockfd, void *buf, size_t  nbytes, int flags);

      成功:以字节计数的消息长度;出错:-1;无可用消息或对方已经按序结束:0;

实现:网络sockfd-取消息msg->内存buf中。

原因:

补充:

(2)       recvfrom()

格式:#include <sys/socket.h>

      ssize_t  recvfrom( int sockfd, void *restrict  buf, size_t  len, int flags, struct sockaddr *restrict addr, socklen_t *restrict  addrlen);

      成功:以字节计数的消息长度;出错:-1;无可用消息或对方已经按序结束:0;

实现:网络sockfd-取消息msg->内存buf中。

原因:

补充:如果addr非空,它将包含数据发送者的套接字端点地址,当调用recvfrom时,需要设置addrlen参数指向一个包含addr所指的套接字缓冲区字节大小的整数。返回时,该整数设为该地址的实际字节大小。因为可以获得发送者的地址,recvfrom通常用于无连接套接字。

 

(3)       recvmsg()

格式:#include <sys/socket.h>

      ssize_t  recvmsg( int sockfd, struct msghdr *msg, int flags);

      成功:以字节计数的消息长度;出错:-1;无可用消息或对方已经按序结束:0;

实现:网络sockfd-取消息msg->内存buf中。

原因:

补充:结构msghdr被recvmsg用于指定接收数据的输入缓冲区。

 

(4)       send()

格式:#include <sys/socket.h>

      ssize_t  send(int sockfd, const  void *buf, size_t  nbytes, int flags);

      成功:返回发送的字节数;出错:-1;

实现:网络sockfd<-取消息msg-内存buf中。

原因:

补充:如果send成功,并不必然表示连接另一端的进程接收数据。所保证的仅是当send成功返回时,数据已经无错误的发送到网络上。

(5)       sendto()

格式:#include <sys/socket.h>

      ssize_t  sendto( int sockfd, const void *restrict  buf, size_t nbytes, int flags,  const struct sockaddr *dest addr, socklen_t * addrlen);

成功:返回发送的字节数;出错:-1;

实现:网络sockfd<-取消息msg-内存buf中。

原因:

补充:适用于无连接的套接字,不能使用send,除非调用connect时预先设定了目标地址,或者采用了sendto来提供另外一种报文发送方式。

 

(6)       sendmsg()

格式:#include <sys/socket.h>

      ssize_t  sendmsg( int sockfd,  const struct msghdr *msg, int flags);

成功:返回发送的字节数;出错:-1;

实现:网络sockfd<-取消息msg-内存buf中。

原因:

补充:可以调用带有msghdr结构的sendmsg来指定多重缓冲区传输数据,和writev很像。

 

传送文件描述符(略,自行实现)

(1)       recv_fd()

(2)       send_fd()

(3)       send_err()


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章