C标准中没有关于操作符重载的规定。基于许多构建系统无法容纳具有相同名称的多个功能的建议,拒绝添加该提议。尽管C ++可以通过以下方法解决此问题:
void foo(int);
int foo(char*);
long foo(char *, char **);
编译为诸如v__foo_i,i__foo_pc和l__foo_pc_ppc之类的函数[编译器使用不同的命名约定,尽管C ++标准禁止在标识符中使用内部双下划线,以便允许编译器以类似的方式给出类似上面的名称]。C标准的作者不希望要求任何编译器更改命名约定以允许重载,因此他们不提供此规范。
对于编译器来说,允许静态和内联函数的重载而不产生命名问题将是可能且有用的。实际上,这将与允许重载外部可链接函数一样有用,因为一个人可能具有头文件:
void foo_zz1(int);
int foo_zz2(char*);
long foo_zz3(char *, char **);
inline void foo(int x) { foo_zz1(x); }
inline int foo(char* st) { foo_zz2(st); }
long foo(char *p1, char **p2) { foo_zz3(p1,p2); }
我记得在看一个嵌入式编译器,用于C和C ++之间的混合,它支持上述作为非标准扩展,但是我对细节并不满意。无论如何,即使某些C编译器确实支持不具有外部链接的函数的重载,C14也不支持它,我也不知道(不幸地)有任何积极的努力将这种功能添加到将来的C标准中。
但是,可以使用宏使GCC支持某种形式的重载,而运算符重载的语言不直接支持这种形式的重载。GCC包含一个内在函数,它将识别表达式是否可以作为编译时常量进行评估。使用此内在函数,可以编写一个宏,该宏可以根据参数以不同的方式(包括通过调用函数)对表达式求值。这在某些情况下很有用,在这种情况下,如果给定一个编译时常量参数,则该公式将被视为一个编译时常量,但如果给定一个变量参数,则将导致可怕的混乱。举一个简单的例子,假设希望对32位值进行位反转。如果该值是常数,则可以通过以下方式实现:
#define nyb_swap(x) \
((((x) & 1)<<3) | (((x) & 2)<<1) | (((x) & 4)>>1) | ((((x) & 8)>>3) )
#define byte_swap(x) \
( (nyb_swap(x)<<4) | nyb_swap((x) >> 4) )
#define word_swap(x) \
( (byte_swap(x)<<24) | (byte_swap((x) >> 8)<<16) | \
(byte_swap((x) >> 16)<<8) | (byte_swap((x) >> 24)) )
像uint32_t x=word_swap(0x12345678);这样的表达式将简单地加载x0x87654321。另一方面,如果该值不是一个常数,则结果将是可怕的:像这样的表达式uint32_t y=word_swap(x);可能会生成许多指令;调用具有部分展开的循环的函数几乎一样快,但是紧凑得多。另一方面,使用循环会防止将结果视为编译时常数。
使用GCC,可以定义一个宏,该宏将在给定常量的情况下使用产生常量的宏,或者在给定变量的情况下调用函数:
#define wswap(x) \
(__builtin_constant_p((x)) ? word_swap((x)) : word_swap_func((x))
这种方法不能完成基于类型的重载可以做的所有事情,但是它可以完成许多重载不能做的事情。