简体   繁体   English

有关指针的C代码

[英]C code about pointers

I've got this simple code that plays with pointers taken from Jon Eriksen's book that I'm trying to compile but gcc gives me warnings in compilation and segmentation fault (core dumped) when I run it. 我已经有了这段简单的代码,可以播放我正在尝试编译的Jon Eriksen的书中的指针,但是gcc在运行它时会在编译和分段错误(内核已转储)中给我警告。

#include<stdio.h>

int main(){
    int i;
    int int_array[5] = {1, 2, 3, 4, 5};
    char char_array[5] = {'a', 'b', 'c', 'd', 'e'};
    unsigned int hacky_nonpointer;

    hacky_nonpointer = (unsigned int)  int_array;   

    for(i=0; i < 5; i++){
        printf("[hacky_nonpointer] points to %p which contains the integer %d\n", hacky_nonpointer, *((int *) hacky_nonpointer));
        hacky_nonpointer = hacky_nonpointer + sizeof(int); // hacky_nonpointer = (unsigned int) ((int *) hacky_nonpointer + 1);
    }

    printf("\n\n\n");

    hacky_nonpointer = (unsigned int) char_array;

    for(i=0; i < 5; i++){
        printf("[hacky non_pointer] points to %p which contains the char %c\n", hacky_nonpointer, *((char *) hacky_nonpointer));
        hacky_nonpointer = hacky_nonpointer + sizeof(char); // hacky_nonpointer = (unsigned int *) ((char *) hacky_nonpointer + 1);

     }
}

Output: 输出:

command line: "gcc -g -o pointer_types5  pointer_types5.c"

pointer_types5.c: In function ‘main’:

pointer_types5.c:16:24: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
     hacky_nonpointer = (unsigned int)  int_array;

pointer_types5.c:20:103: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
  points to %p which contains the integer %d\n", hacky_nonpointer, *((int *) hacky_nonpointer));

pointer_types5.c:20:47: warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘unsigned int’ [-Wformat=]
         printf("[hacky_nonpointer] points to %p which contains the integer %d\n", hacky_nonpointer, *((int *) hacky_nonpointer));

pointer_types5.c:29:24: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
     hacky_nonpointer = (unsigned int) char_array;

pointer_types5.c:35:101: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
 er] points to %p which contains the char %c\n", hacky_nonpointer, *((char *) hacky_nonpointer));

pointer_types5.c:35:48: warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘unsigned int’ [-Wformat=]
         printf("[hacky non_pointer] points to %p which contains the char %c\n", hacky_nonpointer, *((char *) hacky_nonpointer));



command line: "./pointer_types5"
Segmentation fault (core dumped)

some more info about my os: 
uname -a : Linux PINGUIN 4.10.0-33-generic #37-Ubuntu SMP Fri Aug 11 10:55:28 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

This program is wrong, and the advice given in the book is obviously wrong. 这个程序是错误的,书中给出的建议显然是错误的。 A pointer can be converted to a pointer, but the result is implementation-defined. 可以将指针转换为指针,但是结果是实现定义的。 A pointer-to-void can be converted to intprt_t , if such type exists, and then back again to a pointer-to-void. 指针到空隙可被转化为intprt_t ,如果这种类型的存在, 然后再次返回到一个指针到空隙。 This is the only guarantee given by the standard. 这是该标准给出的唯一保证。 Other things might work on one platform or another, but they wouldn't be portable at all - there is no reason why you'd use them in a large program. 其他事物可能会在一个或另一个平台上运行,但它们根本无法移植-没有理由在大型程序中使用它们。

A %p requires a pointer-to-void as an argument. %p需要使用void指针作为参数。 Passing an int has undefined behaviour. 传递int具有不确定的行为。

The things that are attempted in the program cannot be expressed portably in C at all, but possibly a more correct program would be 程序中尝试执行的所有操作都无法完全用C表示,但是可能更正确的程序是

#include <stdio.h>
#include <inttypes.h>

int main(void) {
    int i;
    int int_array[5] = {1, 2, 3, 4, 5};
    char char_array[5] = {'a', 'b', 'c', 'd', 'e'};
    uintptr_t hacky_nonpointer;

    hacky_nonpointer = (uintptr_t)(void *)int_array;   

    for(i=0; i < 5; i++){
        printf("[hacky_nonpointer] points to %p which contains the integer %d\n", (void *)hacky_nonpointer, *((int *)(void *)hacky_nonpointer));
        hacky_nonpointer = hacky_nonpointer + sizeof(int);
    }

    printf("\n\n\n");

    hacky_nonpointer = (uintptr_t)(void *)char_array;

    for(i=0; i < 5; i++){
        printf("[hacky non_pointer] points to %p which contains the char %c\n", (void *)hacky_nonpointer, *((char *)(void *)hacky_nonpointer));
        hacky_nonpointer = hacky_nonpointer + sizeof(char); // hacky_nonpointer = (unsigned int *) ((char *) hacky_nonpointer + 1);

     }
}

however nothing guarantees that hacky_nonpointer = hacky_nonpointer + sizeof(int); 但是, 不能保证hacky_nonpointer = hacky_nonpointer + sizeof(int); would behave as author intended on every platform. 在每个平台上都会表现出作者的预期。 It will however work on many ordinary systems, ie Raspberry Pi, ordinary ARM architectures, modern x86-32 and x86-64 and many more. 但是,它将在许多普通系统上运行,例如Raspberry Pi,普通ARM体系结构,现代x86-32和x86-64等。


This book doesn't teach you C, it teaches author flawed interpretation about what the C should be in his opinion. 本书不会教您C,它会教给作者关于C在他看来应该是什么的错误解释。

Your OS has a 64 bit architecture and the compiler is a 32 bit - based compiler ! 您的OS具有64位体系结构,而编译器是基于32位的编译器! Due to this , there is a mismatch between the size of an integer and pointer (You can check using in-built sizeof() function ). 因此,整数和指针的大小不匹配(您可以使用内置的sizeof()函数进行检查)。
Instead of using an integer , try it with some other data-type (for example a 64-bit long or long long , which is again compiler dependent ) and the warning(s) will be removed ! 代替使用整数,可以尝试使用其他一些数据类型(例如64位long或long long,这又取决于编译器),警告将被删除!

The error messages are clear enough. 错误消息很清楚。 The size of pointer can be greater than the size of int . 指针的大小可以大于int的大小。

If your compiler supports C99 and the type uintptr_t in the header <stdint.h> then the program can look like 如果您的编译器支持C99且标头<stdint.h>的类型为uintptr_t ,则程序可以如下所示:

#include <stdio.h>
#include <stdint.h>

int main(void) 
{
    int i;

    int int_array[5] = {1, 2, 3, 4, 5};

    char char_array[5] = {'a', 'b', 'c', 'd', 'e'};

    uintptr_t hacky_nonpointer;


    hacky_nonpointer = ( uintptr_t )( void * )int_array;   

    for ( i=0; i < sizeof( int_array ) / sizeof( *int_array ); i++  )
    {
        printf( "[hacky_nonpointer] points to %p which contains the integer %d\n", 
            ( void * )hacky_nonpointer, *( int * ) ( void * )hacky_nonpointer );
        hacky_nonpointer = hacky_nonpointer + sizeof (int ); // hacky_nonpointer = (unsigned int) ((int *) hacky_nonpointer + 1);
    }

    printf("\n\n\n");

    hacky_nonpointer = ( uintptr_t ) ( void * )char_array;

    for ( i=0; i < sizeof( char_array ) / sizeof( *char_array ); i++ )
    {
        printf("[hacky non_pointer] points to %p which contains the char %c\n", 
            ( void * )hacky_nonpointer, *( char * )( void * ) hacky_nonpointer );
        hacky_nonpointer = hacky_nonpointer + sizeof(char); // hacky_nonpointer = (unsigned int *) ((char *) hacky_nonpointer + 1);
    }

    return 0;
}

Its output might look like 它的输出可能看起来像

[hacky_nonpointer] points to 0x7fffffd96da0 which contains the integer 1
[hacky_nonpointer] points to 0x7fffffd96da4 which contains the integer 2
[hacky_nonpointer] points to 0x7fffffd96da8 which contains the integer 3
[hacky_nonpointer] points to 0x7fffffd96dac which contains the integer 4
[hacky_nonpointer] points to 0x7fffffd96db0 which contains the integer 5



[hacky non_pointer] points to 0x7fffffd96d90 which contains the char a
[hacky non_pointer] points to 0x7fffffd96d91 which contains the char b
[hacky non_pointer] points to 0x7fffffd96d92 which contains the char c
[hacky non_pointer] points to 0x7fffffd96d93 which contains the char d
[hacky non_pointer] points to 0x7fffffd96d94 which contains the char e

From the C Standard (7.20.1.4 Integer types capable of holding object pointers) 来自C标准(7.20.1.4能容纳对象指针的整数类型)

The following type designates an unsigned integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer: 以下类型指定了一个无符号整数类型,其属性是可以将任何有效的指向void的有效指针转换为该类型,然后再转换回指向void的指针,结果将与原始指针进行比较:

uintptr_t

Take into account that according to the C Standard the function main without parameters shall be declared like 考虑到根据C标准,没有参数的函数main应该声明为

int main( void )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM