size_t ssize_t loff_t 的区别

本文详细介绍了Ssize_t与Size_t这两种数据类型的定义及其在不同平台上的具体实现方式。此外,还对比了它们之间的主要区别,并给出了各自适用的场景。

转自:http://www.cnblogs.com/wenhuisun/archive/2012/07/07/2580643.html

Ssize_t 与size_t

跟踪linux源码得到以下宏:

 

#ifndef _SIZE_T

#define _SIZE_T

typedef __kernel_size_t         size_t;

#endif

 

#ifndef _SSIZE_T

#define _SSIZE_T

typedef __kernel_ssize_t       ssize_t;

#endif

 

在不同平台上,其具有不同的定义:

/* sparc 64 bit */

typedef unsigned long          __kernel_size_t;

typedef long                   __kernel_ssize_t;

 

/* sparc 32 bit */

typedef unsigned int           __kernel_size_t;

typedef int                    __kernel_ssize_t;

这就是两个类型的实际定义,从字面上意思来说:

       Ssize_t = signed size_t

 

使用位置:

       在对于缓冲区大小等等非负值的长度时一般使用 size_t;

       而对于像

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

       ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

       ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);

       ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);

可能失败返回< 0的函数时,则使用ssize_t;

 

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

另外相似的一个类型: loff_t

定义如下:

       #if defined(__GNUC__)

typedef __kernel_loff_t         loff_t;

#endif

是一个long long 类型

#ifdef __GNUC__

typedef long long       __kernel_loff_t;

#endif

 

注重细节,总有一天会成功!

————————————————————华丽的分割线————————————————————————————————


个人小总结:

size_t  为 unsigned  long/int 类型

ssize_t 为 long/int 类型

总而言之  ssize_t  =  signed  size_t

loff_t 为 long long 类型

<think>我们正在讨论Linux中的`size_t`和`ssize_t`类型。根据引用[1]和引用[2][3]的信息,我们可以总结如下: 1. **类型含义**: - `size_t`:表示对象的大小(如内存分配、数组长度等)。它是无符号类型,意味着它不能表示负数。 - `ssize_t`:表示带符号的大小或错误码(特别是可以返回-1表示错误)。它是有符号类型。 2. **符号性**: - `size_t`:无符号(总是大于等于0)。 - `ssize_t`:有符号(可以是负数、零或正数)。 3. **典型用途**: - `size_t`:用于`malloc`、`strlen`、`sizeof`等函数中,这些函数返回的大小不可能为负数。 - `ssize_t`:用于系统调用如`read`、`write`等,因为这些函数在出错时需要返回-1,而在成功时返回非负整数(表示读取或写入的字节数)。 4. **头文件**: - `size_t`:定义在`<stddef.h>`或`<stdlib.h>`等标准头文件中。 - `ssize_t`:定义在`<sys/types.h>`中,通常需要包含`<unistd.h>`(因为系统调用函数如`read`/`write`在此头文件中声明)。 5. **错误处理**: - 使用`ssize_t`的函数(如`read`)在出错时返回-1,并设置`errno`。而使用`size_t`的函数则不会返回负数,因此不能表示错误。 6. **示例代码分析(引用[1]中的代码)**: 原示例代码有误: ```c size_t bytes_read = read(fd, buffer, sizeof(buffer)); if(bytes_read<0) { ... } // 错误:因为size_t是无符号,永远不小于0 ``` 这里应该使用`ssize_t`: ```c ssize_t bytes_read = read(fd, buffer, sizeof(buffer)); if (bytes_read < 0) { ... } // 正确:可以检测错误 ``` 7. **在Linux内核中的使用(引用[2][3])**: 在设备驱动开发中,文件操作结构体`file_operations`中的`read`和`write`函数指针使用`ssize_t`作为返回类型,因为需要返回负的错误码。例如: ```c ssize_t (*read)(struct file *filp, char __user *buf, size_t count, loff_t *f_pos); ssize_t (*write)(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos); ``` 这里,`count`参数是`size_t`类型(无符号,表示要读取或写入的字节数),而返回值是`ssize_t`(有符号,表示实际传输的字节数或负的错误码)。 8. **其他注意事项**: - 在需要表示可能为负的错误码时,必须使用`ssize_t`。 - 在仅表示大小(不可能为负)的场合,使用`size_t`更合适,因为它可以表示更大的正数(因为无符号类型在相同位数下正数范围更大)。 因此,总结如下表: | 类型 | 含义 | 符号性 | 典型用途 | 头文件 | |-----------|------------------------|--------|---------------------------|-------------------| | `size_t` | 对象大小 | 无符号 | `malloc`, `strlen`, `sizeof` | `<stddef.h>`等 | | `ssize_t` | 带符号的大小或错误码 | 有符号 | `read`, `write`系统调用 | `<sys/types.h>` | 现在,我们可以按照要求组织答案。</think>### Linux 中 `size_t` 与 `ssize_t` 的区别与用途详解 #### 1. **核心区别** | 特性 | `size_t` | `ssize_t` | |--------------|------------------------------|--------------------------------| | **含义** | 表示对象大小(内存/数组等) | 表示带符号的大小或错误码 | | **符号性** | 无符号($ \geq 0 $) | 有符号(可为负) | | **错误处理** | 无法表示错误 | 可返回 `-1` 表示错误 | | **典型用途** | `malloc`, `strlen`, `sizeof` | `read`, `write` 等系统调用 | | **头文件** | `<stddef.h>` | `<sys/types.h>` | #### 2. **符号性差异的数学表达** - `size_t`:定义域为 $ [0, 2^n-1] $($ n $ 为位数) $$ \text{size\_t} \in \mathbb{N} $$ - `ssize_t`:定义域为 $ [-2^{n-1}, 2^{n-1}-1] $ $$ \text{ssize\_t} \in \mathbb{Z} $$ #### 3. **实际使用场景** **`size_t` 示例**(无符号,仅表示大小): ```c #include <stddef.h> size_t buffer_size = sizeof(char) * 1024; // 无符号大小计算 ``` **`ssize_t` 示例**(带错误处理): ```c #include <sys/types.h> #include <unistd.h> int fd = open("file.txt", O_RDONLY); char buf[1024]; ssize_t bytes_read = read(fd, buf, sizeof(buf)); // 可能返回-1 if (bytes_read < 0) { // 正确检测错误 perror("read failed"); return -1; } ``` #### 4. **内核级应用(设备驱动开发)** 在 Linux 内核中,文件操作结构体 `file_operations` 明确区分两者: ```c struct file_operations { ssize_t (*read)(struct file*, char*, size_t, loff_t*); // 读函数 ssize_t (*write)(struct file*, const char*, size_t, loff_t*); // 写函数 }; ``` - **参数用 `size_t`**:表示请求的字节数(无符号) - **返回值用 `ssize_t`**:表示实际传输字节数或错误码(负值)[^2][^3] #### 5. **关键注意事项** 1. **错误处理陷阱**: 错误代码示例: ```c size_t bytes = read(fd, buf, 1024); // 错误!size_t无法接收-1 if (bytes < 0) { /* 永远不会触发 */ } ``` 2. **类型转换风险**: 避免强制转换 `size_t` 和 `ssize_t`,可能导致数值截断或逻辑错误。 3. **平台兼容性**: - `size_t`:32/64位系统分别为 4/8 字节 - `ssize_t`:与 `size_t` 同宽度但带符号[^1] #### 6. **典型错误模式分析** ```c // 错误:用size_t接收read()返回值 size_t bytes_read = read(fd, buf, 1024); if (bytes_read == (size_t)-1) { // 危险!-1被转为极大正数 // 实际无法进入此分支 } // 正确:使用ssize_t ssize_t result = read(fd, buf, 1024); if (result < 0) { // 安全检测错误 handle_error(); } ``` > **设计哲学**:`ssize_t` 的引入解决了系统调用需要同时返回**有效数据长度**和**错误状态**的需求,而 `size_t` 专注于描述**无负数的内存维度**。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值