-1

I'm just learning C++ from the basics and in arrays learnt that in C++, there is no bound checking on arrays (Ex: int data[10], accessing data[12] compiler doesn't produce any error and give value in runtime if memory can be accessed)

I noticed the following difference when practicing int and char arrays:

char char_data[10];//char array case
char_data[1] = 'h';
char_data[15] = 'v';//line 1
char_data[11] = '\0';//line 2


int int_data[10];//int array case
int_data[1] = 10;
int_data[15] = 150;//line 3
int_data[11] = 0;//line 4

When I run the above code in main with MSVC++ 14.0 , the code is compiled fine (as no bound checking in C++) but in char array case, the code is crashing/breaking at line 2 where I equate the element to '\0' (Its not considering the index but the value('\0') when the index is out of range) and the assembly produced is as follows:

    10:     data[15] = 'v'; //(no bound check here)
00CF1FE5 B8 01 00 00 00       mov         eax,1  
00CF1FEA 6B C8 0F             imul        ecx,eax,0Fh  
00CF1FED C6 44 0D EC 76       mov         byte ptr data[ecx],76h  

11:     data[11] = '\0';//line 2 (bound check here)
00AF1FFA 89 8D F0 FE FF FF    mov         dword ptr [ebp-110h],ecx  
00AF2000 83 BD F0 FE FF FF 0A cmp         dword ptr [ebp-110h],0Ah  
00AF2007 73 02                jae         main+5Bh (0AF200Bh)  
00AF2009 EB 05                jmp         main+60h (0AF2010h)  
00AF200B E8 6C F1 FF FF       call        ___report_rangecheckfailure        (0AF117Ch)  
00AF2010 8B 95 F0 FE FF FF    mov         edx,dword ptr [ebp-110h]  
00AF2016 C6 44 15 EC 00       mov         byte ptr data[edx],0  

Here, if the value is other than '\0', there is no assembly generated for rangecheck failure. But if I consider the case of int, its not checking the range when the value for an out of range indexis 0('\0' is nothing but 0). I couldn't understand this behavior.

Is this a compiler dependent or this behavior (bound check if value is \0) is same across all the compilers?

Please help!!!

infinite loop
  • 1,309
  • 9
  • 19
  • 1
    The behaviour of any out-of-bound access is always undefined. –  Jun 09 '17 at 04:18
  • Possible duplicate of [Accessing an array out of bounds gives no error, why?](https://stackoverflow.com/questions/1239938/accessing-an-array-out-of-bounds-gives-no-error-why) –  Jun 09 '17 at 04:19
  • 2
    Bounds checking is not required by the standard. If present, it is a compiler extension. Consult your compiler documentation. – cdhowie Jun 09 '17 at 04:19
  • @NickyC, yes it is undefined. But why the compiler is generating code for out of range check when the value is only `'\0'`? – infinite loop Jun 09 '17 at 04:19
  • @NickyC, I know why, acessing an index out of bounds doesn't cause error. but my question is strictly why there is range check (out of bound check when the value is only `\0` – infinite loop Jun 09 '17 at 04:21
  • 2
    Because it's undefined behavior. It could pick your nose, it could jump to a random instruction, it could do a bounds check if it's `\0`. – druckermanly Jun 09 '17 at 04:32
  • 3
    Why are you so determined to find out why _**undefined** behaviour_ behaves in a particular way? This knowledge is unlikely to be of much benefit, because by definition: if something is UB, then you ***cannot*** rely on it! You'd be much better off **not wasting time** digging into something that: (a) could change, (b) is likely to be different on another compiler, and (c) most certainly shouldn't be a feature you depend on within any code you write. – Disillusioned Jun 09 '17 at 04:35
  • 1
    I bet this is a debug build and MSVC generates bound checks on `\0` because it's so common people forget to account for the null terminator when counting the size – Passer By Jun 09 '17 at 05:23

1 Answers1

1

So, you want bounds-checking on your arrays? There is a solution to this, and that is to use std::array which is part of the standard library since C++11 via the header <array>. If you define your array as:

std::array<int, 10> data;

Then all the usual array access can be achieved with operator[] as usual, but you also get the at function (documentation here), which will do a range-test and throw std::out_of_range on failure.

data.at(9) = 0;     // OK
data.at(10) = 0;    // will throw
data.at(5678) = 0;  // will throw

And you are welcome to catch the exception in a try-block if you like. If you don't catch, then you will get a nice program crash at the exact point where you caused the error. And that's nicer than undefined behavior.

Of course, you really shouldn't have to use exception-throwing bounds-checking in ordinary cases. Particularly on an array. You know its size, so don't do silly stuff like accessing values outside its valid range.

paddy
  • 60,864
  • 6
  • 61
  • 103