C 为什么位操作的返回值每次都会改变?

C 为什么位操作的返回值每次都会改变?,c,C,我是计算机科学的初学者。我了解到指针是一种复合数据类型,它指示数据的地址以及数据的类型和大小。指针的类型转换只更改读取大小,但更改起始地址。为了证实这一点,我做了一个实验 请参阅下面的代码。我更改了变量“sample”的指针类型,但我认为它仍然指向sample的第一个字节。除了尺寸,什么都没变。然后我让(char类型)指针向左跳转一个字节(即代码中的“p=p-1”)。之后,我将其转换回短类型。我认为指出的数据是0x..24(…表示0x2456前面的数据)。最后,我使用位操作“大多数都提供(出于网

我是计算机科学的初学者。我了解到指针是一种复合数据类型,它指示数据的地址以及数据的类型和大小。指针的类型转换只更改读取大小,但更改起始地址。为了证实这一点,我做了一个实验

请参阅下面的代码。我更改了变量“sample”的指针类型,但我认为它仍然指向sample的第一个字节。除了尺寸,什么都没变。然后我让(char类型)指针向左跳转一个字节(即代码中的“p=p-1”)。之后,我将其转换回短类型。我认为指出的数据是0x..24(…表示0x2456前面的数据)。最后,我使用位操作“大多数都提供(出于网络安全原因),包括从调用的
main
函数

我不知道为什么我不能得到一个固定值

ASLR可能会解释为什么在操作系统上多次运行程序会产生不同的输出。您的
p
可能指向调用堆栈的某个奇怪位置

当然,请阅读更多关于C11的信息,也就是C11的规范


如果你使用最近编译你的C代码<代码> fo.c>代码>,考虑使用<代码> Gcc-Waldo-O-S fo.c<代码>编译它,然后查看发射的汇编代码<代码> fo.s>代码>。然后你将了解什么值被传递给<代码> Prtff<代码>。它是具体实现的。

< P>从你的代码中,我假设你想要See。ft
0x24
到更高(实际上更低)的字节。尝试
p=p+1
并查看是否得到所需的结果


与其把指针读得很短,不如在黑暗中拍摄一张照片。如果要打印存储在样本的前8位中的值(本例中为1)。注意,这假设内存很小:

short sample = 1;
char* p = (char*)&sample;
p = p - 1;
std::cout << "the first 8 bits of sample: " << (*(short*)p >> 8) << std::endl;
短样本=1;
char*p=(char*)和sample;
p=p-1;

std::cout 8)有一些C代码是由语言保证的,还有一些未定义的代码没有任何特定行为的保证

C语言不允许所有形式的野生类型转换和任意指针算法-如果违反规则,任何事情都可能发生,并且没有确定的结果是有保证的。如果您要分析这种不确定的代码,您可能会得到任何类型的结果,包括程序崩溃

要详细分析您的代码并指出错误所在,请执行以下操作:

  • char*p=(char*)&sample;
    这是一个有效的转换。C语言中有一些特殊规则,允许通过指针转换(如此转换)从任何类型转换为字符类型。在进行此类转换后,您可以取消引用指针
  • 但是,
    char
    特别具有实现定义的符号性。这意味着它可以等于
    signed char
    unsigned char
    ,具体取决于编译器。如果它是有符号的,那么如果取消引用该指针,您可能会遇到意外的输出
  • p=p-1;
    是未定义的行为,任何事情都可能发生。我们只能对指向数组的指针执行指针运算。为了确定指针运算是否有效,指向单值变量(“标量”)的指针将被视为指向具有1项的数组的指针

    指针算法必须导致指针指向已分配数组中从索引
    0
    n+1
    的数组项,其中
    n
    是数组大小。C允许作为特例指向数组之外的1项。但不允许指针算法导致指针指向数组前面的1项在您的代码中完成

    (作为一种特殊情况,为了分析原始数据,我们可以使用字符指针对任何数据类型进行增量迭代。然后将数据视为
    sizeof(data)
    字符的数组。但您的代码不会这样做。)

  • *(short*)p
    也是未定义的行为,因为编译器不知道
    p
    现在指向哪里,也不知道存储在那里的是什么类型。在任何需要对齐访问的系统上,这也是未定义的行为,因为指针现在肯定没有对齐

    最后,系统可能会阻止您现在访问的内存区域,从而导致访问冲突或分段错误。此类错误的性质和结果超出C的范围

  • 如果您的程序尽管存在上述所有问题,但仍能输出一些二进制结果,则该结果可能会受到CPU端性的影响。在第一行
    char*p=(char*)&sample;
    p
    可能指向MS字节或LS字节,具体取决于系统

  • 如果上一条注释中未定义的二进制goo恰好包含MSB集合,则通过左移负整数再次调用未定义的行为


小结:我统计了4种不同的未定义行为和2种实现定义行为。这段代码没有保证或确定的结果。检查结果没有什么可学的。你只能通过分析给出这些结果的代码为什么是错误的来了解一些东西。

你为什么要这样做是否从未定义的行为中导出任何内容?
p=p-1;
是否应该从0x2456中减去1?因为它不会。它会将指针移动到其他内存位置。请确切解释您希望此代码执行的操作。等等,您希望得到0x5656或0x2424或类似的内容吗?@Pranavappu我希望得到0x2400作为指针指向多字节位置的第一个字节,执行
p=p-1
将得到错误的值。如果需要更高的字节,则应执行
p=p+1
。此外,物理内存的布局方式是最低字节位于最左边。因此,您指向的是f
#include<stdio.h>

   int main(void){
       short sample = 0x2456;

       char *p = (char*) &sample; 
       int zero = 0;
       p = p+1;
       printf("%x\n",*((short*)p) << 8 ); 
       return 0;
   }

   #include<stdio.h>

   int main(void){
       short sample = 0x2456;

       char *p = (char*) &sample; 
       int zero = 0x12;
       p = p+1;
       printf("%x\n",*((short*)p);    //will print 1224
       return 0;
   }
short sample = 1;
char* p = (char*)&sample;
p = p - 1;
std::cout << "the first 8 bits of sample: " << (*(short*)p >> 8) << std::endl;