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()


 

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