简体   繁体   English

类型转换为一个指向int的指针。

[英]typecasting a pointer to an int .

I can't understand the output of this program . 我无法理解该程序的输出。 What I get of it is , that , first of all , the pointers p, q ,r ,s were pointing towards null . 我得到的是,首先,指针p,q,r和s指向null。

Then , there has been a typecasting . 然后,有一个类型转换。 But how the heck , did the output come as 1 4 4 8 . 但是输出如何达到1 4 4 8呢? I might be very wrong in my thoughts . 我的想法可能错了。 So , please correct me if I am wrong . 所以,如果我错了,请纠正我。

int main()
{

    int a, b, c, d; 
    char* p = (char*)0; 
    int *q = (int *)0; 
    float* r = (float*)0; 
    double* s = (double*)0; 

    a = (int)(p + 1); 
    b = (int)(q + 1);
    c = (int)(r + 1);
    d = (int)(s + 1);

    printf("%d %d %d %d\n", a, b, c, d); 

    _getch();
    return 0; 
}

Pointer arithmetic, in this case adding an integer value to a pointer value, advances the pointer value in units of the type it points to. 指针算术,在这种情况下,将整数值添加到指针值,以其指向的类型为单位提高指针值。 If you have a pointer to an 8-byte type, adding 1 to that pointer will advance the pointer by 8 bytes. 如果您有一个指向8字节类型的指针,则在该指针上加1将使该指针前进8个字节。

Pointer arithmetic is valid only if both the original pointer and the result of the addition point to elements of the same array object, or just past the end of it. 指针算术仅在原始指针和加法结果都指向同一数组对象的元素时才有效,或者恰好在其末尾。

The way the C standard describes this is ( N1570 6.5.6 paragraph 8): C标准描述的方式是( N1570 6.5.6第8段):

When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. 将具有整数类型的表达式添加到指针或从指针中减去时,结果将具有指针操作数的类型。 If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression. 如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,以使结果数组元素和原始数组元素的下标之差等于整数表达式。
[...] [...]
If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; 如果指针操作数和结果都指向同一数组对象的元素,或者指向数组对象的最后一个元素之后,则求值不应产生溢出; otherwise, the behavior is undefined. 否则,行为是不确定的。 If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated. 如果结果指向数组对象的最后一个元素之后,则不应将其用作被评估的一元*运算符的操作数。

A pointer just past the end of an array is valid, but you can't dereference it. 数组末尾的指针是有效的,但是您不能取消引用它。 A single non-array object is treated as a 1-element array. 单个非数组对象被视为1元素数组。

Your program has undefined behavior. 您的程序具有未定义的行为。 You add 1 to a null pointer. 您将1添加到一个空指针。 Since the null pointer doesn't point to any object, pointer arithmetic on it is undefined. 由于空指针没有指向任何对象,因此它的指针算术是不确定的。

But compilers aren't required to detect undefined behavior, and your program will probably treat a null pointer just like any valid pointer value, and perform arithmetic on it in the same way. 但是不需要编译器检测未定义的行为,您的程序可能会像对待任何有效指针值一样对待空指针,并以相同的方式对其执行算术运算。 So if the null pointer points to address 0 (this is not guaranteed, BTW, but it's very common), then adding 1 to it will probably give you a pointer to address N , where N is the size in bytes of the type it points to. 因此,如果null指针指向地址0 (虽然不能保证,顺便说一句,但这很常见),那么将其添加1 可能会给您一个指向地址N的指针,其中N是它所指向类型的字节大小至。

You then convert the resulting pointer to int (which is at best implementation-defined, will lose information if pointers are bigger than int , and may yield a trap representation ) and you print the int value. 然后,您将结果指针转换为int (最多由实现定义),如果指针大于int ,则将丢失信息,并且可能会产生陷阱表示形式 ),然后打印int值。 The result, on most systems, will probably show you the sizes of char , int , float , and double , which are commonly 1, 4, 4, and 8 bytes, respectively. 在大多数系统上,结果可能会向您显示charintfloatdouble的大小,通常分别为1、4、4和8个字节。

Your program's behavior is undefined, but the way it actually behaves on your system is typical and unsurprising. 程序的行为是不确定的,但是它在系统上的实际行为是典型且毫不奇怪的。

Here's a program that doesn't have undefined behavior that illustrates the same point: 这是一个没有未定义行为的程序, 说明了同一点:

#include <stdio.h>
int main(void) {

    char c;
    int i;
    float f;
    double d;

    char   *p = &c;
    int    *q = &i;
    float  *r = &f;
    double *s = &d;

    printf("char:   %p --> %p\n", (void*)p, (void*)(p + 1));
    printf("int:    %p --> %p\n", (void*)q, (void*)(q + 1));
    printf("float:  %p --> %p\n", (void*)r, (void*)(r + 1));
    printf("double: %p --> %p\n", (void*)s, (void*)(s + 1));

    return 0; 
}

and the output on my system: 和我的系统上的输出:

char:   0x7fffa67dc84f --> 0x7fffa67dc850
int:    0x7fffa67dc850 --> 0x7fffa67dc854
float:  0x7fffa67dc854 --> 0x7fffa67dc858
double: 0x7fffa67dc858 --> 0x7fffa67dc860

The output is not as clear as your program's output, but if you examine the results closely you can see that adding 1 to a char* advances it by 1 byte, an int* or float* by 4 bytes, and a double* by 8 bytes. 输出的结果不如程序的输出清晰,但是如果仔细检查结果,您会发现在char*上加1会使它前进1个字节,将int*float*提前4个字节,将double*提前8个字节字节。 (Other than char , which by definition has a size of 1 bytes, these may vary on some systems.) (除char ,根据定义, char的大小为1个字节,在某些系统上可能有所不同。)

Note that the output of the "%p" format is implementation-defined, and may or may not reflect the kind of arithmetic relationship you might expect. 请注意, "%p"格式的输出是实现定义的,并且可能反映也可能不会反映您可能期望的算术关系。 I've worked on systems (Cray vector computers) where incrementing a char* pointer would actually update a byte offset stored in the high-order 3 bits of the 64-bit word. 我在系统(Cray向量计算机)上工作,其中增加char*指针实际上会更新存储在64位字的高3位中的字节偏移量。 On such a system, the output of my program (and of yours) would be much more difficult to interpret unless you know the low-level details of how the machine and compiler work. 在这样的系统上,除非您了解机器和编译器如何工作的底层细节,否则我的程序输出(以及您的程序输出)将更加难以解释。

But for most purposes, you don't need to know those low-level details. 但是对于大多数目的,您不需要了解那些底层细节。 What's important is that pointer arithmetic works as it's described in the C standard. 重要的是指针算术按照C标准中的描述进行工作。 Knowing how it's done on the bit level can be useful for debugging (that's pretty much what %p is for), but is not necessary to writing correct code. 了解比特级的实现方式对于调试很有用(这几乎就是%p的用途),但对于编写正确的代码则不是必需的。

Adding 1 to a pointer advances the pointer to the next address appropriate for the pointer's type. 向指针加1会将指针前进到适合该指针类型的下一个地址。

When the (null)pointers+1 are recast to int, you are effectively printing the size of each of the types being pointed to by the pointers. 当将(null)pointers + 1重铸为int时,您实际上在打印指针所指向的每种类型的大小。

printf("%d %d %d %d\n", sizeof(char), sizeof(int), sizeof(float), sizeof(double) );

does pretty much the same thing. 做几乎相同的事情。 If you want to increment each pointer by only 1 BYTE , you'll need to cast them to (char *) before incrementing them to let the compiler know 如果只想将每个指针增加1个BYTE ,则需要在将它们递增之前将它们强制转换为(char *)以使编译器知道

Search for information about pointer arithmetic to learn more. 搜索有关指针算法的信息以了解更多信息。

You're typecasting the pointers to primitive datatypes rather type casting them to pointers themselves and then using * (indirection) operator to indirect to that variable value. 您正在将指针类型转换为原始数据类型,而不是将类型强制转换为指针本身,然后使用* (间接)运算符间接指向该变量值。 For instance, (int)(p + 1); 例如, (int)(p + 1); means p ; 均值p ; a pointer to constant, is first incremented to next address inside memory ( 0x1 ), in this case. 在这种情况下,指向常量的指针首先递增到内存( 0x1 )中的下一个地址。 and than this 0x1 is typecasted to an int . 然后将这个0x1类型转换为int This totally makes sense. 这完全有道理。

The output you get is related to the size of each of the relevant types. 您获得的输出与每种相关类型的大小有关。 When you do pointer arithmetic as such, it increases the value of the pointer by the added value times the base type size. 像这样进行指针算术运算时,它将指针值增加的值乘以基本类型的大小。 This occurs to facilitate proper array access. 发生这种情况是为了促进正确的阵列访问。

Because the size of char , int , float , and double are 1, 4, 4, and 8 respectively on your machine, those are reflected when you add 1 to each of the associated pointers. 因为在计算机上charintfloatdouble的大小分别为char和8,所以当您向每个关联的指针加1时,它们的大小就会反映出来。

Edit: 编辑:

Removed the alternate code which I thought did not exhibit undefined behavior, which in fact did. 删除了我认为没有表现出未定义行为的替代代码,实际上确实如此。

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

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