C安全编程教学-预处理器-避免不安全宏参数的副作用(二)_c语言

注:本课程参考文献《C安全编码标准》

 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~

目录

一.背景

二.泛型选择

三.GCC解决方案

四.练习与答案


一.背景

    上节讲到递增递减传递到不安全宏的情况,为了支持所有数据类型,可以使用_Generic选择声明ABS()宏。

二.泛型选择

    由于表达式作为泛型选择的一部分不进行求值,这一解决方案中宏的使用保证只求取宏参数v一次。

#include <complex.h>
#include <math.h>
static inline long long llabs(long long v){
    return v < 0 ? -v : v;
}
static inline long labs(long v){
    return v < 0 ? -v : v;
}
static int sabs(short v){
    return v < 0 ? -v : v;
}
static inline int scabs(signed char v){
    return v < 0 ? -v : v;
}
......
#define ABS(v) _Generic(v, signed char : scabs, \
                           short :sabs, \
                           int : iabs, \
                           long : labs, \
                           long long : llabs, \
                           float : fabsf, \
                           double : fabs, \
                           long double : fabsl, \
                           double complex : cabs, \
                           float complex : cabsf, \
                           long double complex : cabsl)(v)
void func(int n) {
    int m = ABS(++n);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.

三.GCC解决方案

    GCC的__typeof扩展允许声明宏操作数,并为该操作数赋予一个相同类型的临时值。在这个临时值上进行计算,确保原操作数只被计算一次。而GCC的另一个扩展,即语句表达式(statement expression),则允许块语句在需要表达式的地方使用。

#define ABS(x) __extension__ ({ __typeof (x) tmp = x; \
                              tmp < 0 ? -tmp : tmp; })
  • 1.
  • 2.

注:依赖GCC的这类扩展会导致代码不可移植,并且违反“不要引入不必要的平台依赖性”的规则。

四.练习与答案

问题1:为什么使用_Generic选择声明ABS()宏?
答案1:使用_Generic选择声明ABS()宏是为了支持所有数据类型,避免递增递减传递到不安全宏的情况。

问题2:在泛型选择中,表达式作为泛型选择的一部分有什么特性?
答案2:在泛型选择中,表达式作为泛型选择的一部分不进行求值,这一解决方案中宏的使用保证只求取宏参数v一次。

问题3:ABS宏是如何定义以支持多种数据类型的?
答案3:ABS宏是通过_Generic关键字定义,根据不同的数据类型选择对应的绝对值函数,例如int类型使用iabs,float类型使用fabsf等。

问题4:GCC的__typeof扩展有什么作用?
答案4:GCC的__typeof扩展允许声明宏操作数,并为该操作数赋予一个相同类型的临时值,在这个临时值上进行计算,确保原操作数只被计算一次。

问题5:使用GCC的__typeof扩展和语句表达式有什么问题?
答案5:使用GCC的__typeof扩展和语句表达式会导致代码不可移植,并且违反“不要引入不必要的平台依赖性”的规则。

 非常感谢您花时间阅读我的博客,希望这些分享能为您带来启发和帮助。期待您的反馈与交流,让我们共同成长,再次感谢!

👇个人网站👇

 安城安的云世界

 

C安全编程教学-预处理器-避免不安全宏参数的副作用(二)_microsoft_02