任何人都可以解释如何添加a
和b
的逻辑吗?
#include <stdio.h>
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;
}
答案 0 :(得分:20)
隐藏+
:
&p[b]
此表达式相当于
(p + b)
所以我们实际上有:
(int) &p[b] == (int) ((char *) a)[b]) == (int) ((char *) a + b) == a + b
请注意,这在技术上会调用未定义的行为,因为(char *) a
必须指向对象和对象外部的指针算法或者在对象之后调用未定义的行为。
答案 1 :(得分:10)
C标准说E1[E2]
相当于*((E1) + (E2))
。因此:
&p[b] = &*((p) + (b)) = ((p) + (b)) = ((a) + (b)) = a + b
答案 2 :(得分:5)
p[b]
是数组p
的 b-th 元素。这就像写*(p + b)
。
现在,添加&
时,就像写p + b * sizeof(char)
p + b
一样。
现在,您将(int)((char *) a + b)
a + b
。
但是..当你的键盘中仍然有+
时,请使用它。
正如@gerijeshchauhan在评论中澄清的那样,*
和&
是反向操作,它们相互抵消。因此&*(p + b)
为p + b
。
答案 3 :(得分:3)
p成为char
a转换为指向char的指针,从而使p指向具有地址a的内存
然后使用下标运算符到达超出p指向的地址的b偏移量的对象。 b为20,p + 20 = 30020。然后在结果对象上使用address-of运算符将地址转换回int,并且你得到a + b的效果
以下评论可能更容易理解:
#include <stdio.h>
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;
}
参考:here
答案 4 :(得分:2)
char *p;
p
是一个指针(指向大小为1字节的元素)
p=(char *)a;
现在p
指向地址a
sum= (int)&p[b];
p
指针可用作数组p[]
(此数组的起始地址(在内存中)为a
)
p[b]
表示获取 b-th 元素 - 此元素地址为a+b
[(起始地址)a
+ b
(第b个元素*元素大小(1个字节))]
&p[b]
表示在p[b]
获取元素的地址,但其地址为a+b
如果使用指向int的指针(大多数是4个字节)
int* p
p = (int*)a;
您的金额将为 a +(4 * b)
答案 5 :(得分:1)
int a=30000, b=20, sum;
char *p; //1. p is a pointer to char
p = (char *) a;
a
的类型为int
,其值为30000
。上述作业会将值30000
从int
转换为char*
,并将结果存储在p
中。
将整数转换为指针的语义(部分)由C标准定义。引用N1570草案,第6.3.2.3节第5段:
整数可以转换为任何指针类型。除了以前 指定,结果是实现定义的,可能不是 正确对齐,可能不指向引用的实体 类型,可能是陷阱表示。
带有(非规范性)脚注:
用于将指针转换为整数或。的映射函数 整数到指针的目的是与寻址一致 执行环境的结构。
该标准不保证类型int
和char*
的相对大小;要么可能比另一个要大,转换可能会丢失信息。此特定转换的结果不太可能是有效的指针值。如果它是陷阱表示,那么赋值的行为是未定义的。
在您可能正在使用的典型系统上,char*
至少与int
一样大,而整数到指针转换可能只是将构成整数表示的位重新解释为指针值的表示。
sum = (int)&p[b];
根据定义, p[b]
等同于*(p+b)
,其中+
表示指针算术。由于指针指向char
,并且char
定义为1字节,因此添加会使指向地址在内存中增加b
个字节(在本例中为20)。
但是p
可能不是一个有效的指针,因此任何对其执行算术,甚至访问其值的尝试都有未定义的行为。
在实践中,大多数C编译器生成的代码不会执行额外的检查。重点是快速执行正确的代码,而不是检测错误的代码。所以如果之前的p
分配将其设置为与30000
对应的地址,那么将b
或20添加到该地址可能会产生与30020
号码对应的地址。
该地址是(p+b)
的结果;现在[]
运算符隐式地将*
运算符应用于该地址,为您提供该地址指向的对象 - 从概念上讲,这是一个char
对象,存储在与该地址对应的地址整数30020
。
我们立即将&
运算符应用于该对象。有一个特殊情况规则,即将&
应用于[]
运算符的结果等同于仅添加指针;见上述参考标准草案中的6.5.3.2p2。
所以这个:
&p[b]
相当于:
p + b
,正如我上面所说,它产生一个对应于整数值char*
的地址(类型30020
) - 当然,假设整数到指针的转换表现在一定的并且构造和访问无效指针值的未定义行为不会令人感到意外。
最后,我们使用强制转换运算符将此地址转换为int
类型。将指针值转换为整数也是实现定义的,并且可能未定义。引用6.3.2.3p6:
任何指针类型都可以转换为整数类型。除了 之前指定的,结果是实现定义的。如果 结果不能用整数类型表示,行为是 未定义。结果不必在任何值的范围内 整数类型。
char*
大于int
的情况并不少见(例如,我在32位int
的系统上输入此内容和64位char*
)。但在这种情况下,我们相对安全,因为char*
值是转换范围内int
值的结果。我无法保证将给定值从int
转换为char*
并返回int
会产生原始结果,但它通常会以这种方式工作,至少对于在范围内。
所以如果代码恰好正在运行的实现恰好满足了许多特定于实现的假设,那么这段代码可能会产生与{{1}相同的结果}。
顺便说一句,我已经在一个失败的系统上工作过。 Cray T90是一个字寻址机器,硬件地址指向64位字;字节寻址没有硬件支持。但30000 + 20
为8位,因此必须在硬件中构造和操作char
和char*
指针。 void*
指针由64位字指针组成,字节偏移存储在否则未使用的高位3位中。指针和整数之间的转换并没有特别处理这些高阶位;他们只是被复制了。因此char*
和ptr + 1
会产生截然不同的结果。
但是,嘿,你设法在不使用(char*)(int)ptr + 1)
运算符的情况下添加了两个小整数,所以就是这样。
答案 6 :(得分:1)
指针算法的替代方法是使用bitops:
#include <stdio.h>
#include <string.h>
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;
}
答案 7 :(得分:1)
在一个完全不同的说明中,或许正在寻找的是理解二进制加法如何在硬件中完成,具有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,至少,它识别叶子函数并最终将递归优化为迭代版本;可能还有其他编译器)....
可能需要对阴性病例进行更多的研究,但这至少适用于正数。
答案 8 :(得分:1)
/*
by sch.
001010101 = 85
001000111 = 71
---------
010011100 = 156
*/
#include <stdio.h>
#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;
}