C printf在这里做了什么?

C printf在这里做了什么?,c,printf,integer-overflow,C,Printf,Integer Overflow,我只是在测试我对指针的理解,在这样做的时候我做了这个 好吧,这就是我的想法。 所有指向任何类型的指针都保留地址,对吗? 说我声明 char*a,b='f'; a=&b 所以当我试图通过指向char类型的指针访问b的内容时,也就是&b,这是可以的 但是,如果我将int数据类型的地址存储在char类型的指针中(尽管我收到警告:来自不兼容指针类型[-Wincompatible pointer type]的赋值),我没有做错,对吗?我仍在存储一些内存的地址。) intmain(){ //一个字节的int

我只是在测试我对指针的理解,在这样做的时候我做了这个

好吧,这就是我的想法。
所有指向任何类型的指针都保留地址,对吗?
说我声明
char*a,b='f';
a=&b
所以当我试图通过指向char类型的指针访问b的内容时,也就是&b,这是可以的

但是,如果我将int数据类型的地址存储在char类型的指针中(尽管我收到警告:来自不兼容指针类型[-Wincompatible pointer type]的赋值),我没有做错,对吗?我仍在存储一些内存的地址。)

intmain(){
//一个字节的int类型
int a,i;
char*b;
对于(i=-256;i<257;++i){
a=i;
b=&a;
printf(“对于i=%d,存储在a=%d\n”的第一个字节中的值,i,*b);
}
返回0;
}

现在我想它将被允许只读取分配给a的4个字节中的第一个字节,因为我通过指向字符类型的指针进行访问,我希望存储的值最多为255,超出这个值将有一种溢出。
但是发生了一些不同的事情,我只能存储127到-128个whao!!。您是否看到一个大小为一字节的int类型。您可以运行代码查看。


现在假设int类型的大小为一个字节

当a=256时,读取的值应为0,因为0001 0000 0000将只读取第一个字节。
输出是可预测的,直到我们达到a=127,它存储为0111111(从int类型的角度来看是正值)
当a=128时,输出为-128,存储为1000 0000(实际上是-128)
类似地,可以解释其他输出
因此,可以通过假设int-type的大小为一个字节来解释输出,为什么printf会这样做而不是抛出错误。

那么printf到底做了什么呢?

谢谢各位阁下;)

您的系统使用有符号字符,这是完全正常的

您似乎假设/期望
char
无符号的
,这并不总是正确的。它可以是有符号的,也可以是无符号的,但这取决于实现

但是,如果我将int数据类型的地址存储在char类型的指针中(尽管我收到警告:来自不兼容指针类型[-Wincompatible pointer type]的赋值),我没有做错,对吧?我仍在存储一些内存的地址。)

是的,你做错了什么,这就是你得到警告的原因

指针类型的重要性有两个原因:

  • 指针运算是根据对象而不是字节来完成的。如果
    p
    char*
    且其值是
    char
    对象的地址(比如
    0x1000
    ),则
    p+1
    计算为下一个
    char
    对象的地址(
    0x1001
    )。如果
    p
    是一个
    int*
    ,其值是一个4字节
    int
    对象(
    0x2000
    )的地址,
    p+1
    计算为下一个4字节
    int
    对象(
    0x2004
    )的地址

  • 与其他类型一样,不同的指针类型可能具有不同的大小和表示形式。
    int*
    可能与
    char*
    具有不同的表示形式。在大多数现代系统(如x86和x86_64)上,它们是相同的,但也有一些旧的或古怪的体系结构不是这样的

  • 所以可以通过假设int类型的大小为一个字节来解释输出,为什么printf会这样做而不是抛出错误


    问题不在于
    printf
    ,问题在于当您尝试将
    128
    分配给
    *b
    时遇到有符号整数溢出,因为在您的系统上,普通
    char
    占据范围
    [-128..127]
    。不幸的是,有符号整数溢出的行为是未定义的——您的实现不需要以任何特定的方式处理它。我所知道的大多数实现根本不尝试处理它——您只会得到一个意外的值。假设存在多个有符号整数表示,并且假设许多实现依赖于未定义的行为来执行某些优化,那么您几乎可以得到任何结果

    请注意,您的代码也依赖于endian
    a=&b
    (或以后程序中的
    b=&a;
    )是约束冲突——这是不允许的。您可以使用
    -Werror
    编译器标志来获取错误消息。如果您的第一段使用的变量名称与program@M.M:允许违反约束。C标准要求C实现来诊断它们。它不要求C实现禁止它们,并且允许C实现成功地翻译包含约束冲突的程序。@EricPostChil标准不要求实现翻译具有约束冲突的程序,因此我将其描述为“不允许”。在您的术语中,几乎所有内容都是“允许的”(要么因为它是正确的,要么因为标准对包含违反约束或其他未定义行为的程序的行为没有任何要求),因此此类术语是useless@EricPostpischil没错,我有点过于简单化了。我把代码降价了也许这会有帮助。谢谢。谢谢,是的,我的系统使用有符号的字符。
    int main(){
    // int type of one byte
        int a, i ;
        char *b;
    
        for(i = -256 ;i < 257; ++i){
            a = i;
            b = &a;
            printf("for i = %d, value stored in first byte of a = %d\n",i ,*b);
        }
        return 0;    
    }