Каково поведение «» number и почему оно компилируется?

#c #segmentation-fault

#c #ошибка сегментации

Вопрос:

Код успешно компилирует его, но я не могу понять, почему при определенных значениях number программа завершает работу, а при других значениях — нет. Может ли кто-нибудь объяснить поведение добавления a long int с a char* , которое использует компилятор?

 #include <iostream>

int main()
{
    long int number=255;
    std::cout<< "Value 1 : " << std::flush << (""   number) << std::flush << std::endl;
    number=15155;
    std::cout<< "Value 2 : " << std::flush << (""   number) << std::flush << std::endl;
    return 0;
}
  

Результаты тестирования:

 Value 1 : >                                                                            
Value 2 : Segmentation fault  
  

Примечание: я не ищу решение о том, как добавить строку с числом.

Комментарии:

1. Для этого наверняка есть дубликат

2. Интуитивно я бы сказал "" , что возвращает адрес первого элемента буквенной пустой строки; затем вы добавляете number к этому адресу; затем operator<< пытается разыменовать этот новый адрес для чтения строки, что является неопределенным поведением.

3. Обманщик объясняет, что происходит, когда вы добавляете a char . Ваш случай является более простым, поскольку char он повышен до int первого.

4. Для более наглядного объяснения этого явления: замените "" на "Hello, World!" и number=255; на number=7;

5. @stef Спасибо за объяснение, которое решило мою проблему

Ответ №1:

В C "" это const char[1] массив, который распадается на const char* указатель на первый элемент массива (в данном случае на '' нулевой завершитель строкового литерала).

Добавление целого числа к указателю выполняет арифметику указателя, которая увеличивает адрес памяти в указателе на указанное количество элементов типа, как объявлен указатель (в данном случае, char ).

Итак, в вашем примере ... << ("" number) << ... эквивалентно ... << amp;""[number] << ... или в более общем смысле:

 const char *ptr = amp;""[0];
ptr = reinterpret_cast<const char*>(
    reinterpret_cast<const uintptr_t>(ptr)
      (number * sizeof(char))
);
... << ptr << ...
  

Это означает, что вы выходите за пределы массива при number любом значении, отличном от 0, поэтому ваш код имеет неопределенное поведение, и при operator<< попытке разыменования недопустимого указателя, который вы ему даете, может произойти что угодно.

В отличие от многих языков сценариев, ("" number) это неправильный способ преобразования целого числа в строку в C . Вместо этого вам нужно использовать явную функцию преобразования, такую как std::to_string() , например:

 #include <iostream>
#include <string>

int main()
{
    long int number = 255;
    std::cout << "Value 1 : " << std::flush << std::to_string(number) << std::flush << std::endl;
    number = 15155;
    std::cout << "Value 2 : " << std::flush << std::to_string(number) << std::flush << std::endl;
    return 0;
}
  

Или вы можете просто разрешить std::ostream::operator<< обрабатывать это преобразование для вас, например:

 #include <iostream>

int main()
{
    long int number = 255;
    std::cout<< "Value 1 : " << std::flush << number << std::flush << std::endl;
    number = 15155;
    std::cout<< "Value 2 : " << std::flush << number << std::flush << std::endl;
    return 0;
}
  

Ответ №2:

Виновата арифметика указателей.

A const char* принимается operator<< , но не будет указывать на допустимый адрес памяти в вашем примере.

Если вы включите -Wall , вы увидите предупреждение компилятора об этом:

 main.cpp: In function 'int main()':
main.cpp:6:59: warning: array subscript 255 is outside array bounds of 'const char [1]' [-Warray-bounds]
    6 |     std::cout<< "Value 1 : " << std::flush << (""   number) << std::flush << std::endl;
      |                                                           ^
main.cpp:8:59: warning: array subscript 15155 is outside array bounds of 'const char [1]' [-Warray-bounds]
    8 |     std::cout<< "Value 2 : " << std::flush << (""   number) << std::flush << std::endl;
      |                                                           ^
Value 1 :  q
  

Живая демонстрация