Like Tree5Likes

Undefined behavior with pointers to different arrays.

This is a discussion on Undefined behavior with pointers to different arrays. within the C Programming forums, part of the General Programming Boards category; Hello to all I have a question please. I have read that the result of comparison between pointers who point ...

  1. #1
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    293

    Undefined behavior with pointers to different arrays.

    Hello to all

    I have a question please. I have read that the result of comparison between pointers who point to different arrays is undefined.

    For example assume tha we have :

    Code:
    #include<stdio.h>
    
    int main(void)
    {
        int arr2[2]={2,3} , arr1[2];
    
        int *p1 = arr1 , *p2 = arr2;
    
        printf("%d , %d" , arr1 , arr2);
    
        if( p1 < p2 ) // do sth ...     UNDEFINED BEHAVIOR 
    
       
    
        return 0;
    }
    My question is : Why the behavior is undefined ? arr1 and arr2 will have different addressed of course but my reflection is the result is not sure because compiler may give a higher address to arr1 for example 2000 and arr2 will have 1000 or something. I am right?

    Thank you in advance

  2. #2
    Registered User
    Join Date
    Nov 2012
    Posts
    1,057
    The way you explained it seems right. But the way I see it is this: if it is known that p1 != p2 (which is true if they are distinct arrays) then clearly either p1 < p2 or p1 > p2 is true. The problem I have is: what decision are you actually trying to perform by asking this question. I mean, suppose you know p1 definitely comes before p2 in memory. OK... now what computation can you perform based on this knowledge?

  3. #3
    Registered User
    Join Date
    Nov 2012
    Posts
    1,057
    By the way, if the two arrays are members of a struct then it should be well defined which one comes first because the memory layout is specified in order that you specify the members of the struct. However it is not defined how much "gap space" there is between the members. That's sometimes a surprising aspect that comes up.

  4. #4
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    293
    Quote Originally Posted by c99tutorial View Post
    The way you explained it seems right. But the way I see it is this: if it is known that p1 != p2 (which is true if they are distinct arrays) then clearly either p1 < p2 or p1 > p2 is true. The problem I have is: what decision are you actually trying to perform by asking this question. I mean, suppose you know p1 definitely comes before p2 in memory. OK... now what computation can you perform based on this knowledge?
    I don't want to do something particular of course. I was wondering If I have understood why the comparison between two pointers pointing to different arrays is UB. You said to me that my reflection is right and I think it is true because we can't predict on this case where compiler will put the arrays in the memory. That is all I don't want something else.

    Finally I agree with you if we have a struct with two variables int a and b for example then a comes first in the memory if it is declared first and there is no way to predict the "gap space" due to allignment.

  5. #5
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,457
    Quote Originally Posted by Mr.Lnx View Post
    I don't want to do something particular of course. I was wondering If I have understood why the comparison between two pointers pointing to different arrays is UB. You said to me that my reflection is right and I think it is true because we can't predict on this case where compiler will put the arrays in the memory. That is all I don't want something else.
    Yes, that is correct. The standard gives no guarantee as to the order or relative location of variables, particularly local automatic variables. I would guess that historically, different OSes and architectures may benefit from different memory layouts, so the standard left it up to the implementation. In modern times that still may be true, but also, this lack of guarantee helps support things like address space layout randomization, which is used to help thwart attack vectors like buffer overflows.

    Along with struct members being guaranteed in a particular order, array elements are as well, and they don't have padding ("gaps") between them. If p1 started at address 1000, and ints were 4 bytes, then &p[0] = 1000, &p[1] = 1004, &p[2] = 1008, etc.

  6. #6
    Stoned Witch Barney McGrew's Avatar
    Join Date
    Oct 2012
    Location
    astaylea
    Posts
    420
    Are you sure it has undefined behaviour, rather than unspecified behaviour? If it were true I think that would make it impossible to implement memmove() in a standard-compliant manner.
    i dont believe in competition in da field of cboard posts, u see, i believe in a collection of posts each 2 be admired for der own personal statement. when in doubt, ask Willy!

  7. #7
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    293
    Quote Originally Posted by Barney McGrew View Post
    Are you sure it has undefined behaviour, rather than unspecified behaviour? If it were true I think that would make it impossible to implement memmove() in a standard-compliant manner.
    Well I don't know what unspecified behavior is. I read it from my book that the issue we discuss here it is called undefined behavior.

    @anduril462 I didn't mean that the "gap space" has to do with the distance among the element of the arrays. The elements of array have particular distance of course which comes from -> (sizeof(type_of_element)). The gap space (padding) has to do with the members of the struct.

  8. #8
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,457
    @Barney McGrew:
    For a little bit, I thought you were right. It seemed intuitive, and I couldn't think of why it would be undefined instead of implementation-defined or unspecified. I looked at the standard to be sure, and found this:
    Quote Originally Posted by C11 6.5.8 p2
    Constraints
    2
    One of the following shall hold:
    both operands have real type;
    both operands are pointers to qualified or unqualified versions of compatible object
    types; or
    both operands are pointers to qualified or unqualified versions of compatible
    incomplete types.
    That last item there implies that the operation itself is valid, i.e. you are allowed to compare pointers, so long as the types of each pointer are compatible. But then, if you read on (emphasis mine)
    Quote Originally Posted by C11 6.5.8 p5
    5
    When two pointers are compared, the result depends on the relative locations in the
    address space of the objects pointed to. If two pointers to object or incomplete types both
    point to the same object, or both point one past the last element of the same array object,
    they compare equal. If the objects pointed to are members of the same aggregate object,
    pointers to structure members declared later compare greater than pointers to members
    declared earlier in the structure, and pointers to array elements with larger subscript
    values compare greater than pointers to elements of the same array with lower subscript
    values. All pointers to members of the same union object compare equal. If the
    expression P points to an element of an array object and the expression Q points to the
    last element of the same array object, the pointer expression Q+1 compares greater than
    P. In all other cases, the behavior is undefined.
    So, if the pointers both refer to the same object1, or both to some part of the same aggregate object (struct, union or array), then it's okay. Comparing pointers to different objects though, is undefined.

    1 In this case, it seems a strict < or > would always be false, and <= or >= would always be true. Somewhat pointless (you could use == or !=) but allowed nonetheless.

  9. #9
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,457
    Quote Originally Posted by Mr.Lnx View Post
    Well I don't know what unspecified behavior is. I read it from my book that the issue we discuss here it is called undefined behavior.
    Question 11.33
    Quote Originally Posted by Mr.Lnx View Post
    @anduril462 I didn't mean that the "gap space" has to do with the distance among the element of the arrays. The elements of array have particular distance of course which comes from -> (sizeof(type_of_element)). The gap space (padding) has to do with the members of the struct.
    Yeah, I figured. Just being thorough.

  10. #10
    Registered User
    Join Date
    Jun 2011
    Posts
    2,272
    Comparing pointers to different objects though, is undefined.
    If I understand correctly, this case seems to be explicitly spelled out in Section J2 ("Undefined Behavior"):

    Pointers that do not point to the same aggregate or union (nor just beyond the same
    array object) are compared using relational operators (6.5.8).
    anduril462 and Salem like this.

  11. #11
    Registered User
    Join Date
    Mar 2011
    Posts
    406
    Isn't it only the ordinality of the pointers that is undefined?
    (as opposed to, eg, two pointers to elements in the same array)

    Wouldn't the comparison still give you a valid result?

    -

  12. #12
    Registered User
    Join Date
    Jun 2005
    Posts
    6,252
    Quote Originally Posted by megafiddle View Post
    Isn't it only the ordinality of the pointers that is undefined?
    (as opposed to, eg, two pointers to elements in the same array)
    No it is not. The act of comparison itself has undefined behaviour.

    The standard does that, so I understand, because not all machine architectures allow comparison of pointers that point into unrelated areas of memory. For example, if one structure is stored in ROM, and the other in RAM, it is not always possible to compare their addresses (machine instructions might not even exist to do the comparison). But different pointers can be used to access data in either type of memory.

    Quote Originally Posted by megafiddle View Post
    Wouldn't the comparison still give you a valid result?
    Depends what you mean by a "valid result". Since the behaviour is undefined, any behaviour is permitted. Giving a true result, giving a false result, or reflashing your BIOS are all possible consequences.
    stahta01 likes this.
    Right 98% of the time, and don't care about the other 3%.

  13. #13
    Registered User
    Join Date
    Mar 2011
    Posts
    406
    Quote Originally Posted by grumpy View Post
    No it is not. The act of comparison itself has undefined behaviour.

    The standard does that, so I understand, because not all machine architectures allow comparison of pointers that point into unrelated areas of memory. For example, if one structure is stored in ROM, and the other in RAM, it is not always possible to compare their addresses (machine instructions might not even exist to do the comparison). But different pointers can be used to access data in either type of memory.
    That makes sense.

    So would assignments also be a problem then?
    If p1 points to array1, and p2 points to array2, would p1 = p2 be undefined?

    -

  14. #14
    Registered User
    Join Date
    Jun 2005
    Posts
    6,252
    Quote Originally Posted by megafiddle View Post
    That makes sense.

    So would assignments also be a problem then?
    If p1 points to array1, and p2 points to array2, would p1 = p2 be undefined?
    No. A pointer can hold any value which represents a valid address in memory. If the assignment compiles (i.e. p1 and p2 are of compatible types) the result of the assignment is defines. Of course, after doing p1 = p2, a comparison of p1 with the address of any element of array1 gives undefined behaviour. But it CAN then be compared with address of any element of array2.

    It is the nature of what is pointed at (the pointee, if you like) that determined if the comparison has defined or undefined behaviour, not the representation of the pointer itself.
    Right 98% of the time, and don't care about the other 3%.

  15. #15
    Registered User
    Join Date
    Mar 2011
    Posts
    406
    Quote Originally Posted by grumpy View Post
    No. A pointer can hold any value which represents a valid address in memory. If the assignment compiles (i.e. p1 and p2 are of compatible types) the result of the assignment is defines. Of course, after doing p1 = p2, a comparison of p1 with the address of any element of array1 gives undefined behaviour. But it CAN then be compared with address of any element of array2.

    It is the nature of what is pointed at (the pointee, if you like) that determined if the comparison has defined or undefined behaviour, not the representation of the pointer itself.
    So are there then different "types" of pointers to same type? Something that is unaccessable to the programmer?

    Is it that a proper conversion will be done for assignment, but not for comparison?

    I appreciate the help and information. I'm just trying to understand where the danger actually is in the comparison,
    aside from it providing a possibly useless result.

    -

Page 1 of 3 123 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Is this not undefined behavior?
    By Syscal in forum C Programming
    Replies: 6
    Last Post: 07-15-2013, 01:07 AM
  2. Undefined behavior
    By jim mcnamara in forum C Programming
    Replies: 2
    Last Post: 02-18-2013, 10:14 PM
  3. Static vs. Dynamic Arrays, Getting Undefined Behavior
    By StefPrez in forum C++ Programming
    Replies: 11
    Last Post: 01-28-2012, 10:39 PM
  4. Is x=x++; Undefined Behavior?
    By envec83 in forum C Programming
    Replies: 5
    Last Post: 10-04-2011, 01:27 AM
  5. Undefined behavior from VC6 to 2k5
    By m37h0d in forum C++ Programming
    Replies: 10
    Last Post: 06-22-2011, 07:56 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21