使用指针指向int来声明字符串

时间:2015-08-06 08:46:54

标签: c pointers

我正在尝试使用指向int

的指针初始化字符串
#include <stdio.h>
int main()
{
   int *ptr = "AAAA";
   printf("%d\n",ptr[0]);
   return 0;
}

此代码的结果为 1094795585
任何机构可以解释这种行为以及为什么代码给出了这个答案吗?

4 个答案:

答案 0 :(得分:4)

  

我正在尝试使用指向int

的指针初始化字符串

字符串文字 "AAAA"属于char[5]类型,是由char类型的五个元素组成的数组。

分配时:

int *ptr = "AAAA";

你实际上必须使用显式广告(因为类型不匹配):

int *ptr = (int *) "AAAA";

但是,它仍然可能无效,因为intchar对象可能有不同的对齐要求。换句话说:

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
  • CPU有小端字节排序(虽然它并不重要,因为每个字母都是相同的)
  • 默认字符集为ASCII(字母'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

独立于字节序。