C++
您通过将两个任意类型的数字转换为unsigned char *
并访问每个字节来将它们相加的方法不会起作用,原因有几个:
- 正如您注意到的,
unsigned char
只能保存从0到255的值,因此任何产生大于255的值的加法都将溢出并绕回.您需要考虑进位位并将其传播到下一个字节.例如,如果将255 + 1
相加,则得到进位为1
的0
,应将其添加到下一个字节.
- 您还需要考虑系统的字节顺序,这决定了多字节值的字节在内存中的存储方式.例如,在小端系统中,最先存储最低有效字节,而在大端系统中,最先存储最高有效字节.您可以使用
htons
或ntohs
函数在主机和网络字节顺序之间进行转换,该顺序是大端的.
- 不能通过简单地将
float
或double
值的字节相加来将它们相加,因为它们的表示形式与整数不同.它们使用一种名为IEEE 754的格式,该格式由三部分组成:符号、指数和尾数.您需要了解这种格式是如何工作的,以及如何对其执行算术运算.或者,您可以使用union
作为不同类型访问相同的内存,但这是不可移植的,并且可能违反严格的别名规则.
实现泛型Add函数的更好方法是使用C++中的模板,它允许您编写适用于不同类型的代码,而不会强制转换或丢失精度.例如:
template <typename T>
void add(T a, T b, T& c) {
c = a + b;
}
此函数适用于任何支持+
运算符的类型,如int
、float
、double
等.您也可以为具有自定义加法方式的其他类型重载此函数,如std::string
或std::vector
.
要使用此函数,只需使用适当的类型调用它:
int main() {
int a = 255;
int b = 1;
int c = 0;
add(a, b, c);
printf("%d + %d = %d\n", a, b, c);
}
该程序的输出为:
255 + 1 = 256
我希望这能帮助您理解为什么您的方法不起作用,以及如何改进它.有关模板、字符顺序和IEEE 754格式的更多信息,请访问以下链接:
- https://www.cplusplus.com/doc/oldtutorial/templates/个
- https://en.wikipedia.org/wiki/Endianness个
- https://en.wikipedia.org/wiki/IEEE_754个
C (After-edit)
我很抱歉没有注意到问题是关于C而不是C++.我之前的回答是基于C++模板的,而C中没有这些模板.下面是一个仅使用C功能的更新答案.
如果您只想在C中实现一个通用的Add函数,您有几个 Select :
- 您可以使用在编译时展开为适当类型和操作的宏.例如:
#define add(a, b, c) ((c) = (a) + (b))
此宏适用于任何支持+
运算符的类型,但它有一些缺点,例如多个参数求值和缺乏类型判断.
- 您可以使用空指针并将类型的大小作为附加参数传递.例如:
void add(void *a, void *b, void *c, size_t size) {
// copy the bytes from a and b to c
memcpy(c, a, size);
// add the bytes from b to c
for (size_t i = 0; i < size; i++) {
// get the pointers to the current bytes
unsigned char *c_byte = (unsigned char *)c + i;
unsigned char *b_byte = (unsigned char *)b + i;
// add the bytes with carry
unsigned char sum = *c_byte + *b_byte;
unsigned char carry = sum < *c_byte;
*c_byte = sum;
// propagate the carry to the next byte
if (carry) {
size_t j = i + 1;
while (j < size && ++*((unsigned char *)c + j) == 0) {
j++;
}
}
}
}
此函数适用于任何整数类型,但它有一些缺点,例如不处理字符顺序,也不适用于浮点类型.
- 您可以使用不同类型的联合和标记来指示哪种类型处于活动状态.例如:
typedef enum { INT, FLOAT, DOUBLE } tag_t;
typedef union {
int i;
float f;
double d;
} value_t;
typedef struct {
tag_t tag;
value_t value;
} generic_t;
void add(generic_t *a, generic_t *b, generic_t *c) {
// check that the types are compatible
if (a->tag != b->tag) {
fprintf(stderr, "Cannot add different types\n");
exit(1);
}
// set the tag of the result
c->tag = a->tag;
// perform the addition based on the tag
switch (a->tag) {
case INT:
c->value.i = a->value.i + b->value.i;
break;
case FLOAT:
c->value.f = a->value.f + b->value.f;
break;
case DOUBLE:
c->value.d = a->value.d + b->value.d;
break;
default:
fprintf(stderr, "Unknown type\n");
exit(1);
}
}
该函数适用于包含在联合中的任何类型,但它有一些缺点,例如标记需要额外的内存,并且对于其他类型不可扩展.
正如您所看到的,在C中没有针对泛型编程的完美解决方案.您必须在简单性、效率、可移植性和灵活性之间进行权衡.有关C语言泛型编程的更多信息,您可以访问以下链接:
- How to make generic function using void * in c?个
- C generic type as function argument input个