我正在尝试使用指向int
的指针初始化字符串#include <stdio.h>
int main()
{
int *ptr = "AAAA";
printf("%d\n",ptr[0]);
return 0;
}
此代码的结果为 1094795585
任何机构可以解释这种行为以及为什么代码给出了这个答案吗?
答案 0 :(得分:4)
我正在尝试使用指向int
的指针初始化字符串
字符串文字 "AAAA"
属于char[5]
类型,是由char
类型的五个元素组成的数组。
分配时:
int *ptr = "AAAA";
你实际上必须使用显式广告(因为类型不匹配):
int *ptr = (int *) "AAAA";
但是,它仍然可能无效,因为int
和char
对象可能有不同的对齐要求。换句话说:
alignof(char) != alignof(int)
可能会举行。另外,在这一行:
printf("%d\n", ptr[0]);
您正在调用未定义的行为(因此,如果编译器喜欢,则可能会打印"Hello from Mars"
),因为ptr[0]
取消引用ptr
,从而违反 strict别名规则。
请注意,转换int * ---> char *
和读取对象为char *
是有效的,但不是相反。
此代码的结果为1094795585
结果很有意义,但为此,您需要以有效的形式重写您的程序。它可能看起来像:
#include <stdio.h>
#include <string.h>
union StringInt {
char s[sizeof("AAAA")];
int n[1];
};
int main(void)
{
union StringInt si;
strcpy(si.s, "AAAA");
printf("%d\n", si.n[0]);
return 0;
}
要解读它,您需要做出一些假设,具体取决于您的实施。例如,如果
int
类型需要四个字节(即sizeof(int) == 4
)'A'
表示为0x41
,即十进制的65
然后,您可以推断,si.n[0]
在记忆中保留:
0x41 0x41 0x41 0x41
是二进制文件:
01000001 ...
符号(最重要)位未设置,因此它等于:
65 * 2^24 + 65 * 2^16 + 65 * 2^8 + 65 =
65 * (2^24 + 2^16 + 2^8 + 1) = 65 * 16843009 = 1094795585
答案 1 :(得分:3)
1094795585
是正确的。
'A'
的ASCII值为65
,即十六进制为0x41
。
其中四个使0x41414141
等于十进制的1094795585
。
您通过执行65656565
获得了值65*100^0 + 65*100^1 + 65*100^2 + 65*100^3
,但这是错误的,因为字节 1 可以包含256个不同的值,而不是100个。
因此,正确的计算结果为65*256^0 + 65*256^1 + 65*256^2 + 65*256^3
,即1094795585
。
更容易想到十六进制的内存,因为一个十六进制数字直接对应半个字节 1 ,所以两个十六进制数字是一个完整字节 1 (参见0x41
)。而在十进制中,255
适合单个字节 1 ,但256
不适合。
CHAR_BIT == 8
,1
答案 2 :(得分:0)
65656565这是&#34; AAAA&#34;的价值的错误表示。你是分别代表每个角色和&#34; AAAA&#34;存储为array.Its转换为1094795585,因为%d
标识符打印十进制值。使用以下命令在gdb
中运行此命令:
x/8xb (pointer) //this will show you the memory hex value
x/d (pointer) //this will show you the converted decimal value
答案 3 :(得分:0)
@zenith给了你预期的答案,但是你的代码调用了UB。无论如何,你可以用几乎正确的方式证明这一点:
#include <stdio.h>
int main()
{
int i, val;
char *pt = (char *) &val; // cast a pointer to any to a pointer to char : valid
for (i=0; i<sizeof(int); i++) pt[i] = 'A'; // assigning bytes of int : UB in general case
printf("%d 0x%x\n",val, val);
return 0;
}
在一般情况下,分配int的字节是UB,因为C标准表示 [for]有符号整数类型,对象表示的位应分为三组:值位,填充位和签名位。并且注释添加填充位的某些组合可能会生成陷阱表示,例如,如果一个填充 bit是奇偶校验位。
但是在常见架构中,没有填充位,并且所有位值都对应于有效数字,因此操作在所有常见系统上都是有效的(但依赖于实现)。它仍然依赖于实现,因为int的大小不是标准的,也不是字节序。
所以:在没有填充位的32位系统上,上面的代码将产生
1094795585 0x41414141
独立于字节序。