请原谅我,如果这是一个微不足道的问题 - 我通常是一个控制系统人(plc和自动化),但最近我发现自己参与了一些嵌入式微控制器和PC项目。
假设我有一个接受指向“命令字节”数组的指针的函数,通常长度为5或10个字节,如下所示:
char cmd_i2c_read(unsigned char *cmd, unsigned short cmd_len) { ... }
我想解码命令字节(* cmd)。
是否有更好的形式:
创建指示每个字节用途的局部变量:
unsigned char device_address = cmd[2];
unsigned char register_address = cmd[3];
unsigned char num_bytes = cmd[4];
// use the local variables:
if(num_bytes &le 0xFF) {
do_stuff(device_address, register_address, num_bytes);
}
创建本地指针:
unsigned char *device_address = &cmd[2];
unsigned char *register_address = &cmd[3];
unsigned char *num_bytes = &cmd[4];
// use the pointers:
if(*num_bytes &le 0xFF) {
do_stuff(*device_address, *register_address, *num_bytes);
}
直接索引* cmd数组:
if(cmd[4] <= 0xFF) {
do_stuff(cmd[2], cmd[3], cmd[4]);
}
答案 0 :(得分:4)
选项1很清楚,但有点罗嗦。我根本不喜欢2,3很难理解。就个人而言,我更喜欢使用结构来做这种事情。
typedef struct {
unsigned char whatever[2];
unsigned char device_address;
unsigned char register_address;
unsigned char num_bytes;
} CMD;
CMD * pcmd = (CMD *)&cmd[0];
// use the local variables:
if(num_bytes ≤ 0xFF) {
do_stuff(pcmd->device_address, pcmd->register_address, pcmd->num_bytes);
答案 1 :(得分:3)
我更喜欢第3项,但归结为偏好。
答案 2 :(得分:3)
对于更大的数据结构,我会使用数字2,即使用指针,这样您就不必复制值。但在这种情况下,差异并不显着,我认为* /&amp;略微降低可读性。
答案 3 :(得分:2)
绝对是#1。它使代码的其余部分更具可读性,并且使用正常变量所做的指针会无缘无故地使问题复杂化。编译器将优化您从#3获得的任何微观性能增益。
答案 4 :(得分:1)
如果是我,我会将其写为#3,但使用数组索引的符号名称来提高可读性: -
#define DEVICE_ADDRESS 2
#define REGISTER_ADDRESS 3
#define NUM_BYTES 4
if (cmd[NUM_BYTES] <= 0xFF) {
do_stuff(cmd[DEVICE_ADDRESS], cmd[REGISTER_ADDRESS], cmd[NUM_BYTES]);
}
你当然可以用const int,enums等替换宏。我喜欢这个选项的原因是其他两个选项需要使用额外的局部变量。编译器可能会也可能不会优化它们,具体取决于它的实现和您选择的优化级别,但它们对我来说似乎是一种不必要的额外间接。
答案 5 :(得分:0)
我最喜欢1,它比其他人更可读。
如果性能是一个重要问题(我的意思很重要,比如“我们需要每增加0.01%的速度,我们就可以获得”),你将不得不进行基准测试,因为它真的取决于编译器哪个序列最终将以最快的代码结束( 1可能有不必要的副本,2可能包含由于指针别名限制的超级负载,3如果寄存器分配器真的搞砸可能会导致超级负载)
答案 6 :(得分:0)
对我来说,这取决于你对缓冲区做什么,
尽管所有事情都是平等的,但我可能更喜欢让缓冲区成为一个结构(假设对齐警告),如果不这样做,则直接索引缓冲区,尽管没有魔术数字。