A
long integer is
at least
32 bits
-Wall -Wshadow -Wwrite-strings -Wextra -Wconversion -std=c99 -pedantic
)它应该告诉你。
test.c:20:28: warning: implicit conversion loses integer precision: 'long' to 'uint16_t'
(aka 'unsigned short') [-Wconversion]
tmp.registers[i] = strtol(tmp.vals, &end, 10);
~ ^~~~~~~~~~~~~~~~~~~~~~~~~~
但是,这不会导致故障。你将失去16位,标志的变化会做一些有趣的事情。
#include <stdio.h>
#include <inttypes.h>
int main() {
long big = 1234567;
uint16_t small = big;
printf("big = %ld, small = %" PRIu16 "\n", big, small);
}
知道
strtoul
读一本书
未签名
long
,验证它是否足够小以适合,并显式强制转换它。
unsigned long num = strtoul(tmp.vals, &end, 10);
if( 0 <= num && num < 65536 ) {
tmp.registers[i] = (uint16_t)num;
}
else {
fprintf(stderr, "%lu is too large to fit in the register\n", num);
}
更有可能
tmp.registers
(可能的话)
buffer
)没有正确初始化并将点分配给垃圾。如果你只是宣布
tmp
在堆栈上这样:
Registers tmp;
这只分配内存给
tmp公司
,而不是它所指的东西。而且里面会有垃圾。
tmp.寄存器
会指向记忆中的某个随机点。当你试着给它写信时,它会出错。。。最终。
需要分配寄存器数组。
size_t how_many = 10;
uint16_t *registers = malloc( sizeof(uint16_t) * how_many );
Thing tmp = {
.registers = registers,
.vals = NULL
};
how_many
次。但在阅读输入时,你不能确定这一点。您的循环可能正在读取无限多个寄存器。如果它超过了我们分配的10,它将再次开始写入其他人的内存和segfault。
registers
它到底有多远。我们可以在循环中完成,但它确实属于结构。
typedef struct {
uint16_t *registers;
char *vals;
size_t max;
size_t size;
} Registers;
当我们在做的时候,把初始化放到一个函数中,这样我们就可以确保每次都能可靠地完成。
void Registers_init( Registers *registers, size_t size ) {
registers->registers = malloc( sizeof(uint16_t) * size );
registers->max = size;
registers->size = 0;
}
和我们的边界检查一样。
void Registers_push( Registers *registers, uint16_t num ) {
if( registers->size == registers->max ) {
fprintf(stderr, "Register has reached its limit of %zu\n", registers->max);
exit(1);
}
registers->registers[ registers->size ] = (uint16_t)num;
registers->size++;
}
现在我们可以安全地添加寄存器了。或者至少它会很好地出错。
Registers registers;
Registers_init( ®isters, 10 );
tmp.vals = strtok(buffer, delimiter);
while (tmp.vals != NULL) {
unsigned long num = strtoul(tmp.vals, &end, 10);
if( 0 <= num && num < 65536 ) {
Registers_push( &tmp, (uint16_t)num );
}
else {
fprintf(stderr, "%lu is too large to fit in the register\n", num);
}
tmp.vals = strtok(NULL, delimiter);
i++;
}
此时,我们正在实现一个大小绑定数组。这是一个很好的练习,但是对于生产代码来说
use an existing library such as GLib
它提供了自增长阵列和更多功能。