sum(加2个数字)没有加号运算符

任何人都可以解释如何添加ab的逻辑?

 #include  int main() { int a=30000, b=20, sum; char *p; p = (char *) a; sum = (int)&p[b]; //adding a and b! printf("%d",sum); return 0; } 

+隐藏在这里:

 &p[b] 

这个表达相当于

 (p + b) 

所以我们实际上有:

 (int) &p[b] == (int) ((char *) a)[b]) == (int) ((char *) a + b) == a + b 

请注意,这在技术上会调用未定义的行为,因为(char *) a必须指向对象,并且指针算术在对象外部或者在对象之后调用未定义的行为。

C标准说E1[E2]相当于*((E1) + (E2)) 。 因此:

  &p[b] = &*((p) + (b)) = ((p) + (b)) = ((a) + (b)) = a + b 

p[b]是数组p 的第b个元素。 这就像写*(p + b)

现在,当添加&它就像写: p + b * sizeof(char) ,即p + b
现在,你将有(int)((char *) a + b) ,它是…… a + b

但是……当你的键盘上还有+ ,请使用它。


由于@gerijeshchauhan在评论中澄清, *&是反向操作,他们互相取消。 所以&*(p + b)p + b

  1. p成为char的指针

  2. a转换为指向char的指针,从而使p指向具有地址a的内存

  3. 然后使用下标运算符到达超出p指向的地址的b偏移量的对象。 b为20,p + 20 = 30020。 然后在结果对象上使用address-of运算符将地址转换回int,并且你得到了a + b的效果

以下评论可能更容易理解:

 #include  int main() { int a=30000, b=20, sum; char *p; //1. p is a pointer to char p = (char *) a; //2. a is converted to a pointer to char and p points to memory with address a (30000) sum = (int)&p[b]; //3. p[b] is the b-th (20-th) element from address of p. So the address of the result of that is equivalent to a+b printf("%d",sum); return 0; } 

参考: 这里

 char *p; 

p是一个指针(对于大小为1字节的元素)


 p=(char *)a; 

现在p指向带有地址a内存


 sum= (int)&p[b]; 

p指针可以用作数组p[] (此数组的起始地址(在内存中)是a

p[b]表示获得第b个元素 – 此元素地址为a+b

[(起始地址) a + b (第b个元素*元素大小(1个字节))]

&p[b]表示在p[b]获取元素的地址,但其地址为a+b


如果使用指向int的指针(大多数是4个字节)

 int* p p = (int*)a; 

你的总和将是+(4 * b)

  int a=30000, b=20, sum; char *p; //1. p is a pointer to char p = (char *) a; 

a的类型为int ,值为30000 。 上面的赋值将值30000int转换为char*并将结果存储在p

将整数转换为指针的语义(部分)由C标准定义。 引用N1570草案,第6.3.2.3节第5段:

整数可以转换为任何指针类型。 除非先前指定,否则结果是实现定义的,可能未正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示。

(非规范性)脚注:

用于将指针转换为整数或整数到指针的映射函数旨在与执行环境的寻址结构一致。

该标准不保证intchar*类型的相对大小; 要么可能比另一个要大,转换可能会丢失信息。 此特定转换的结果不太可能是有效的指针值。 如果它是陷阱表示,则赋值的行为是未定义的。

在您可能正在使用的典型系统上, char*至少与int一样大,并且整数到指针转换可能只是将构成整数表示的位重新解释为指针值的表示。

  sum = (int)&p[b]; 

p[b]根据定义等同于*(p+b) ,其中+表示指针算术。 由于指针指向char ,并且char按定义为1字节,因此添加使指向地址在存储器中前进b字节(在本例中为20)。

但是p可能不是一个有效的指针,所以任何对它执行算术,甚至访问它的值的尝试都有未定义的行为。

实际上,大多数C编译器生成的代码不执行额外的检查。 重点是快速执行正确的代码,而不是检测错误的代码。 因此, 如果先前对p分配将其设置为对应于数字30000的地址,则将b或20添加到该地址将可能产生对应于数字30020的地址。

该地址是(p+b)的结果; 现在, []运算符隐式地将*运算符应用于该地址,为您提供该地址指向的对象 – 从概念上讲,这是一个存储在对应于整数30020的地址的char对象。

我们立即将&运算符应用于该对象。 有一个特殊情况规则说,应用& []运算符的结果等同于只添加指针; 见上述参考标准草案中的6.5.3.2p2。

所以这:

 &p[b] 

相当于:

 p + b 

正如我上面所说,它产生一个对应于整数值30020的地址(类型为char* ) – 当然,假设整数到指针的转换以某种方式表现,并且构造和访问的未定义行为无效的指针值不会令人感到意外。

最后,我们使用强制转换运算符将此地址转换为int类型。 将指针值转换为整数也是实现定义的,并且可能未定义。 引用6.3.2.3p6:

任何指针类型都可以转换为整数类型。 除了之前指定的以外,结果是实现定义的。 如果结果无法以整数类型表示,则行为未定义。 结果不必在任何整数类型的值范围内。

char*大于int的情况并不少见(例如,我在具有32位int和64位char*的系统上键入它)。 但是在这种情况下我们相对安全,因为char*值是转换范围内int值的结果。 不能保证将给定值从int转换为char*并返回int将产生原始结果,但它通常以这种方式工作,至少对于范围内的值。

因此, 如果代码恰好运行的实现恰好满足了许多特定于实现的假设,那么此代码可能会产生与30000 + 20相同的结果。

顺便说一下,我曾经在一个失败的系统上工作过。 Cray T90是一个字寻址机器,硬件地址指向64位字; 字节寻址没有硬件支持。 但是char是8位,所以char*void*指针必须在硬件中构造和操作。 char*指针由64位字指针组成,字节偏移存储在否则未使用的高位3位中。 指针和整数之间的转换并没有特别处理这些高阶位; 他们只是被复制了。 因此ptr + 1(char*)(int)ptr + 1)可以产生非常不同的结果。

但是,嘿,你已经设法添加两个小整数而不使用+运算符,所以就是这样。

指针算法的替代方法是使用bitops:

 #include  #include  unsigned addtwo(unsigned one, unsigned two); unsigned addtwo(unsigned one, unsigned two) { unsigned carry; for( ;two; two = carry << 1) { carry = one & two; one ^= two; } return one; } int main(int argc, char **argv) { unsigned one, two, result; if ( sscanf(argv[1], "%u", &one ) < 1) return 0; if ( sscanf(argv[2], "%u", &two ) < 1) return 0; result = addtwo(one, two); fprintf(stdout, "One:=%u Two=%u Result=%u\n", one, two, result ); return 0; } 

在一个完全不同的说明中,或许正在寻找的是理解二进制加法如何在硬件中完成,具有XOR,AND和位移。 换句话说,算法是这样的:

 int add(int a, int b) { int partial_sum = a ^ b; int carries = a & b; if (carries) return add(partial_sum, carries << 1); else return partial_sum; } 

或迭代等价物(尽管,gcc,至少,识别叶函数并优化递归到迭代版本;可能其他编译器也是如此)....

可能需要对负面案例进行更多的研究,但这至少适用于正数。

 /* by sch. 001010101 = 85 001000111 = 71 --------- 010011100 = 156 */ #include  #define SET_N_BIT(i,sum) ((1 << (i)) | (sum)) int sum(int a, int b) { int t = 0; int i = 0; int ia = 0, ib = 0; int sum = 0; int mask = 0; for(i = 0; i < sizeof(int) * 8; i++) { mask = 1 << i; ia = a & mask; ib = b & mask; if(ia & ib) if(t) { sum = SET_N_BIT(i,sum); t = 1; /*i(1) t=1*/ } else { t = 1; /*i(0) t=1*/ } else if (ia | ib) if(t) { t = 1; /*i(0) t=1*/ } else { sum = SET_N_BIT(i,sum); t = 0; /*i(1) t=0*/ } else if(t) { sum = SET_N_BIT(i,sum); t = 0; /*i(1) t=0*/ } else { t = 0; /*i(0) t=0*/ } } return sum; } int main() { int a = 85; int b = 71; int i = 0; while(1) { scanf("%d %d", &a, &b); printf("%d: %d + %d = %d\n", ++i, a, b, sum(a, b)); } return 0; }