使用 |= 而不是 = 的具体原因
Specific reasons to use |= instead of =
我目前正在查看 Linux 内核(热管理)中的一些代码。在某些地方有一个 return 值用于表示错误,在函数开始时将其设置为 0。然后,当调用可能失败的函数时,使用 |=
而不是 =
将其设置为新值。这是一个例子:
int ti_bandgap_read_temperature(struct ti_bandgap *bgp, int id,
int *temperature)
{
u32 temp;
int ret;
ret = ti_bandgap_validate(bgp, id);
if (ret)
return ret;
spin_lock(&bgp->lock);
temp = ti_bandgap_read_temp(bgp, id);
spin_unlock(&bgp->lock);
ret |= ti_bandgap_adc_to_mcelsius(bgp, temp, &temp);
if (ret)
return -EIO;
*temperature = temp;
return 0;
}
ti_bandgap_validate
的定义是:
/**
* ti_bandgap_validate() - helper to check the sanity of a struct ti_bandgap
* @bgp: struct ti_bandgap pointer
* @id: bandgap sensor id
*
* Checks if the bandgap pointer is valid and if the sensor id is also
* applicable.
*
* Return: 0 if no errors, -EINVAL for invalid @bgp pointer or -ERANGE if
* @id cannot index @bgp sensors.
*/
static inline int ti_bandgap_validate(struct ti_bandgap *bgp, int id)
所以,如果我的推理是正确的,在调用 ti_bandgap_adc_to_mcelsius()
时,ret
的值必须是 0
(否则该函数已经退出)。那么这里使用|=
而不是=
的原因是什么呢?使用全零模式执行 "or" 只会返回正常模式。这是针对通常情况的某种优化,即函数 returning 没有失败(即 return 值 0
)?还是我缺少其他一些区别?此代码在 ARM 架构上 运行,因此它可能需要针对该平台进行特定优化。
没有理由在这种情况下使用 |=
。如您所述,到达此行时 ret
必须为 0 ,否则它会更早返回。它还引入了一个不必要的额外操作。
如评论中所述,此运算符实际上在this commit中更改为=
。提交评论指出:
Avoid confusing |= on error values.
在这种情况下,没有理由使用 |=
但是,如果您正在跟踪许多可能出错的函数,并且 return 如果它们出错为 return代码,模式是
boolean error = false
error |= doFirstStep(...);
error |= doSecondStep(...);
error |= doThirdStep(...);
if (error) {
printf("error occurred: %s\n", strerror(errno));
}
它是 C 中较少使用的模式,偶尔用于与 C 有某种亲和力的语言。在 C 语言中,大量的 C 库函数 return 和 "error code" 通常是0 表示操作成功。
使用此模式时,用户依赖 return 零作为成功条件。这意味着上述 log_and_recover()
可能会从 error.h 静态变量中提取错误消息,这在 C #include <error.h>
例程中很常见。
---- 继续为什么这经常用在 int 字段上----
您还会看到此模式,其中 int
包含错误。
int error = 0; // or a variable that's defined to zero
error |= doFirstStep(...);
error |= doSecondStep(...);
error |= doThirdStep(...);
if (error != 0) {
... some error handling ...
}
当你看到这个的时候,跟上面的思路是一样的,只不过开发者结合了两种模式。通常用于打包配置参数的位域模式被用来打包多种错误。通常,发生这种情况时,您会发现类似于
的错误列表
#define ERROR_NO_DISK (1<<1);
#define ERROR_NO_NETWORK (1<<2);
#define ERROR_NO_SANITY (1<<3);
对于大多数项目而言,return 多个错误并将它们作为一个错误来处理并不是很明智;但有时在错误抑制很重要时会这样做。例如,如果您无法将消息从客户端传输到主机,您可以将各种 "failure to open a socket"、"failure to write to socket"、"failure to copy to buffer" 等失败抑制为通用的 [=35] =].在一个层面上,整个顶级工作流程失败了,如果需要,原因的详细信息仍然有些可用。
我目前正在查看 Linux 内核(热管理)中的一些代码。在某些地方有一个 return 值用于表示错误,在函数开始时将其设置为 0。然后,当调用可能失败的函数时,使用 |=
而不是 =
将其设置为新值。这是一个例子:
int ti_bandgap_read_temperature(struct ti_bandgap *bgp, int id,
int *temperature)
{
u32 temp;
int ret;
ret = ti_bandgap_validate(bgp, id);
if (ret)
return ret;
spin_lock(&bgp->lock);
temp = ti_bandgap_read_temp(bgp, id);
spin_unlock(&bgp->lock);
ret |= ti_bandgap_adc_to_mcelsius(bgp, temp, &temp);
if (ret)
return -EIO;
*temperature = temp;
return 0;
}
ti_bandgap_validate
的定义是:
/**
* ti_bandgap_validate() - helper to check the sanity of a struct ti_bandgap
* @bgp: struct ti_bandgap pointer
* @id: bandgap sensor id
*
* Checks if the bandgap pointer is valid and if the sensor id is also
* applicable.
*
* Return: 0 if no errors, -EINVAL for invalid @bgp pointer or -ERANGE if
* @id cannot index @bgp sensors.
*/
static inline int ti_bandgap_validate(struct ti_bandgap *bgp, int id)
所以,如果我的推理是正确的,在调用 ti_bandgap_adc_to_mcelsius()
时,ret
的值必须是 0
(否则该函数已经退出)。那么这里使用|=
而不是=
的原因是什么呢?使用全零模式执行 "or" 只会返回正常模式。这是针对通常情况的某种优化,即函数 returning 没有失败(即 return 值 0
)?还是我缺少其他一些区别?此代码在 ARM 架构上 运行,因此它可能需要针对该平台进行特定优化。
没有理由在这种情况下使用 |=
。如您所述,到达此行时 ret
必须为 0 ,否则它会更早返回。它还引入了一个不必要的额外操作。
如评论中所述,此运算符实际上在this commit中更改为=
。提交评论指出:
Avoid confusing |= on error values.
在这种情况下,没有理由使用 |=
但是,如果您正在跟踪许多可能出错的函数,并且 return 如果它们出错为 return代码,模式是
boolean error = false
error |= doFirstStep(...);
error |= doSecondStep(...);
error |= doThirdStep(...);
if (error) {
printf("error occurred: %s\n", strerror(errno));
}
它是 C 中较少使用的模式,偶尔用于与 C 有某种亲和力的语言。在 C 语言中,大量的 C 库函数 return 和 "error code" 通常是0 表示操作成功。
使用此模式时,用户依赖 return 零作为成功条件。这意味着上述 log_and_recover()
可能会从 error.h 静态变量中提取错误消息,这在 C #include <error.h>
例程中很常见。
---- 继续为什么这经常用在 int 字段上----
您还会看到此模式,其中 int
包含错误。
int error = 0; // or a variable that's defined to zero
error |= doFirstStep(...);
error |= doSecondStep(...);
error |= doThirdStep(...);
if (error != 0) {
... some error handling ...
}
当你看到这个的时候,跟上面的思路是一样的,只不过开发者结合了两种模式。通常用于打包配置参数的位域模式被用来打包多种错误。通常,发生这种情况时,您会发现类似于
的错误列表#define ERROR_NO_DISK (1<<1);
#define ERROR_NO_NETWORK (1<<2);
#define ERROR_NO_SANITY (1<<3);
对于大多数项目而言,return 多个错误并将它们作为一个错误来处理并不是很明智;但有时在错误抑制很重要时会这样做。例如,如果您无法将消息从客户端传输到主机,您可以将各种 "failure to open a socket"、"failure to write to socket"、"failure to copy to buffer" 等失败抑制为通用的 [=35] =].在一个层面上,整个顶级工作流程失败了,如果需要,原因的详细信息仍然有些可用。