LINUX.ORG.RU

Какие правила языка C++ здесь используются?

 ,


0

3

Вот имеем два примера:

const int x = 5;

int main(int argc, char** argv)
{
    int x = x;
    cout << x;
    return 0;
}
Результат 0.

const int x = 5;

int main(int argc, char** argv)
{
    int y = x;
    cout << y;
    return 0;
}
Результат 5.

Я бы мог это понять, если бы небыло третьего примера:

const int x = 5;

int main(int argc, char** argv)
{
    int x[x];
    cout << sizeof(x) / sizeof(int);
    return 0;
}
Результат 5.

Вот. Какие свойства/правила языка обеспечивают такое поведение?

★★★★★

Ответ на: комментарий от fsb4000

Чтобы узнать про это, нужно читать предупреждения компилятора.

#include <iostream>
const int x = 5;

int main(int argc, char** argv)
{
    int x = x;
    std::cout << x;
    return 0;
}
src/main.cpp: In function ‘int main(int, char**)’:
src/main.cpp warning: declaration of ‘x’ shadows a global declaration [-Wshadow]
     int x = x;
         ^
src/main.cpp note: shadowed declaration is here
 const int x = 5;
           ^
src/main.cpp warning: unused parameter ‘argc’ [-Wunused-parameter]
 int main(int argc, char** argv)
              ^~~~
src/main.cpp warning: unused parameter ‘argv’ [-Wunused-parameter]
 int main(int argc, char** argv)
                           ^~~~
src/main.cpp warning: ‘x’ is used uninitialized in this function [-Wuninitialized]
     int x = x;
         ^
#include <iostream>
const int x = 5;

int main(int argc, char** argv)
{
    int x[x];
    std::cout << sizeof(x) / sizeof(int);
    return 0;
}
src/main.cpp: In function ‘int main(int, char**)’:
src/main.cpp warning: declaration of ‘x’ shadows a global declaration [-Wshadow]
     int x[x];
            ^
src/main.cpp note: shadowed declaration is here
 const int x = 5;
           ^
src/main.cpp warning: unused parameter ‘argc’ [-Wunused-parameter]
 int main(int argc, char** argv)
              ^~~~
src/main.cpp warning: unused parameter ‘argv’ [-Wunused-parameter]
 int main(int argc, char** argv)

fsb4000 ★★★★ ()
Ответ на: комментарий от fsb4000

shadowed declaration

Оно. Зачем сувать вилку в розетку и рассуждать, почему они не поставили там УЗО, почему не сделали конструкцию, не позволяющую засунуть конкретно вилку (а гибкую проволочку можно). И так далее.

Зачем светит Солнце?

I-Love-Microsoft ★★★★★ ()
Ответ на: комментарий от Xintrea
$ g++-7 -v
Using built-in specs.
COLLECT_GCC=g++-7
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.2.0-1ubuntu1~16.04' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.2.0 (Ubuntu 7.2.0-1ubuntu1~16.04)
fsb4000 ★★★★ ()
Ответ на: комментарий от Xintrea

У меня такие предупреждения выставлены в шаблоне makefile

	WARNINGS = -Wall -Wextra -pedantic -Wstrict-aliasing=2 -Wformat-security     \
	    -Wstrict-overflow=5 -Wfloat-equal -Wformat-extra-args -Wshadow -Winit-self\
	    -Wswitch-default -Wformat-nonliteral -Wuninitialized -Wdouble-promotion   \
	    -Walloca -Wdouble-promotion -Wduplicated-branches -Wduplicated-cond       \
	    -Wconversion -Wpadded -Wlogical-not-parentheses -Walloc-zero -Wcast-qual  \
	    -Wformat-y2k -Wcast-align -Wlogical-op -Wwrite-strings -Wsign-conversion  \
	    -Wredundant-decls -Wmissing-include-dirs -Wswitch-enum -Wstack-protector
	WARNINGS_CPP_ONLY = -Wuseless-cast -Wold-style-cast -Woverloaded-virtual     \
	    -Wsuggest-final-methods -Wsuggest-override -Wzero-as-null-pointer-constant\
	    -Wsuggest-final-types -Weffc++ -Wsubobject-linkage
	WARNINGS_C_ONLY = -Wc++-compat -Wbad-function-cast
Потом вот так, эти предупреждения попадают в CFLAGS и CXXFLAGS
FLAGS = $(OPTIMIZE) $(WARNINGS) $(INCLUDE) $(LTO) $(DEFINES) $(OPENMP) $(SECURITY) $(DEBUG)
CFLAGS = $(CSTANDARD) $(FLAGS) $(WARNINGS_C_ONLY)
CXXFLAGS = $(CXXSTANDARD) $(FLAGS) $(WARNINGS_CPP_ONLY)
Вот тут можно прочитать об этих опциях: https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc/Warning-Options.html

fsb4000 ★★★★ ()
Ответ на: комментарий от fsb4000

Секунду, у меня в cmake прописано:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")


а в Makefile никаких -Wall нет, как-то не приходило в голову это проверять. Пока не понял почему опция не используется.

Xintrea ★★★★★ ()
Ответ на: комментарий от Xintrea

-Wall стоит, предупреждений нет.

GCC не все варнинги по -Wall включает. Как минимум надо еще -Wextra. Ну и все равно в данном случае надо еще -Wshadow.

В clang все просто: -Weverything и потом -Wno-${неугодный_варнинг}

KennyMinigun ★★★★★ ()

А к чему все эти сложности и страшные слова в комментариях?

1) У тебя объявлен x, но ты его объявляешь его еще раз, а это значит что прошлое объявление не действует и действует только новое

2) Все и так понятно

3) Ты объявил массив x, а то что объявлено выше - это переменная, они друг друга не перекрывают и соответственно оба объявления работают как надо.

Надеюсь меня поправят если что-то не так.

Kronick ()

int x = x;

Первый x — декларатор. Второй x — инициализатор.

int x[x];

x[x] — декларатор. Поэтому иксы разные.

Переменная доступна для использования после декларатора, хоть сразу в инициализаторе. Отсюда и разница в поведении.

А 0 в первом случае это неинициализированное значение, т.е. UB.

xaizek ★★★★★ ()
Ответ на: комментарий от Kronick

1) У тебя объявлен x, но ты его объявляешь его еще раз, а это значит что прошлое объявление не действует и действует только новое

Тут маленький нюанс: не действует уже на этапе инициализации нового.

3) Ты объявил массив x, а то что объявлено выше - это переменная, они друг друга не перекрывают и соответственно оба объявления работают как надо.

Вот тут вопрос, почему они друг друга не перекрывают, если имена у них одинаковые, пусть и разные типы.

Xintrea ★★★★★ ()
Ответ на: комментарий от fsb4000

У меня список почти совпадает, я ещё -Wold-style-cast добавляю.

DELIRIUM ☆☆☆☆☆ ()
Ответ на: комментарий от xaizek

Переменная доступна для использования после декларатора, хоть сразу в инициализаторе.

Вот это в мемориз надо.

Xintrea ★★★★★ ()

Там выше уже ответили, но все же: области видимости, можно просто добавить блок из операторных скобок и в ней декларировать и инициализировать переменные с такими же именами, что и выше, переиспользуя их.

JAkutenshi ★★ ()
Ответ на: комментарий от Dudraug

День у меня такой, запутанный. Я к тому это написал, что человек образно говоря «вилку в розетку сует», но удивляется почему его током шарахнуло.

I-Love-Microsoft ★★★★★ ()

В момент вычисления инициализирующего значения переменная x уже определена (известен её тип и размер), поэтому она перекрывает собой глобальную переменную. В момент же вычисления размера массива он ещё не определён (ибо размер таки неизвестен), поэтому он не перекрывает глобальную переменную.

KivApple ★★★★★ ()
Ответ на: комментарий от JAkutenshi

это пример из учебника, а ОП хочет разобраться с ньюансами языка, что очень полезно

А может наоборот вредно. Потому что такие задачи решает грамотное тестирование. Ловкое хождение на грани UB и других подобных вещей - до добра не доведет.

Вот в первом примере у него получился 0 - это правильный результат? Я не очень в этом уверен.

I-Love-Microsoft ★★★★★ ()
Ответ на: комментарий от former_anonymous

В чём кривость и где именно тут «неоднозначность»?

anonymous ()
Ответ на: комментарий от Xintrea

Тебе они и не нужны, «перекрытие» - это фича и никаких проблем с этим нет, если ты не табуретка, конечно же. И эта фича используется повсеместно.

Единственное, что тебе может понадобиться - это: warning: ‘x’ is used uninitialized in this function [-Wuninitialized]

anonymous ()
Ответ на: комментарий от I-Love-Microsoft

Вот в первом примере у него получился 0 - это правильный результат? Я не очень в этом уверен.

Выше гцц тебе уже дал ответ -

warning: ‘x’ is used uninitialized in this function

anonymous ()
Ответ на: комментарий от Xintrea

С CMAKE_CXX_FLAGS разобрался. Эту переменную можно объявлять только после project(), иначе она молча не будет применяться.

Xintrea ★★★★★ ()
Последнее исправление: Xintrea (всего исправлений: 2)
Ответ на: комментарий от I-Love-Microsoft

Вот в первом примере у него получился 0 - это правильный результат? Я не очень в этом уверен.

Это неинициализованная переменная. Но похоже что gcc с какой-то версии начало инитить нулем. Раньше обязательно был бы мусор, сейчас четко ноль.

Xintrea ★★★★★ ()
Последнее исправление: Xintrea (всего исправлений: 1)
Ответ на: комментарий от Xintrea

Раньше обязательно был бы мусор, сейчас четко ноль.

Ясно. И для всех ли это переменных теперь так? Или было и раньше, но включалось флагом.

I-Love-Microsoft ★★★★★ ()
Ответ на: комментарий от Dudraug

Вот, смотри что умные люди fluorite говорят.

Это все знают.

Я бы не был столь категоричен :)

Xintrea ★★★★★ ()
Ответ на: комментарий от Dudraug

Я это к тому, что книжка - не стандарт. А ты говорил именно про книги. Поэтому и спрашиваю на какой странице. Тебе же не сложно это сказать.

Xintrea ★★★★★ ()
Ответ на: комментарий от Xintrea

Тебе же не сложно это сказать.

Сложно, у меня их под рукой нет, я не помню где, искать я не буду. Я между прочим работаю.

Dudraug ★★★★★ ()

Решил посмотреть что другие компиляторы пишут

#include <iostream>
const int x = 5;

int main(int argc, char** argv)
{
    int x = x;
    std::cout << x;
    return 0;
}
FreeBSD 11.1, clang-4
src/main.cpp:6:9: warning: declaration shadows a variable in the global namespace [-Wshadow]
    int x = x;
        ^
src/main.cpp:2:11: note: previous declaration is here
const int x = 5;
          ^
src/main.cpp:4:14: warning: unused parameter 'argc' [-Wunused-parameter]
int main(int argc, char** argv)
             ^
src/main.cpp:4:27: warning: unused parameter 'argv' [-Wunused-parameter]
int main(int argc, char** argv)
                          ^
src/main.cpp:6:13: warning: variable 'x' is uninitialized when used within its own initialization [-Wuninitialized]
    int x = x;
        ~   ^
src/main.cpp:2:11: warning: unused variable 'x' [-Wunused-const-variable]
const int x = 5;
          ^
5 warnings generated.
MSVC 2017, не компилирует.
Предупреждение	C4459	объявление "x" скрывает глобальное объявление
Предупреждение	C4100	argv: неиспользованный формальный параметр
Предупреждение	C4100	argc: неиспользованный формальный параметр
Ошибка	C4700	использована неинициализированная локальная переменная "x"

#include <iostream>
const int x = 5;

int main(int argc, char** argv)
{
    int x[x];
    std::cout << sizeof(x) / sizeof(int);
    return 0;
}

FreeBSD 11.1, clang-4

src/main.cpp:6:9: warning: declaration shadows a variable in the global namespace [-Wshadow]
    int x[x];
        ^
src/main.cpp:2:11: note: previous declaration is here
const int x = 5;
          ^
src/main.cpp:4:14: warning: unused parameter 'argc' [-Wunused-parameter]
int main(int argc, char** argv)
             ^
src/main.cpp:4:27: warning: unused parameter 'argv' [-Wunused-parameter]
int main(int argc, char** argv)
                          ^
3 warnings generated.
MSVC 2017, забавно C26494 не переведён на русский
Предупреждение	C26494	Variable 'x' is uninitialized. Always initialize an object (type.5: http://go.microsoft.com/fwlink/p/?LinkID=620421)
Предупреждение	C4459	объявление "x" скрывает глобальное объявление
Предупреждение	C4100	argv: неиспользованный формальный параметр
Предупреждение	C4100	argc: неиспользованный формальный параметр

fsb4000 ★★★★ ()
Ответ на: комментарий от Dudraug

А ты помнишь все, что в книжках написано, и работаешь не имея их под рукой? Я не издеваюсь, а реально спрашиваю. Мне это всегда было удивительно. Я когда прогать сажусь, обязательно книжки рядом кладу, потому что без них как без рук, особенно если нужно поковырять чужой код.

Или ты настолько круто английский знаешь, что с лёту понимаешь стандарт и всю терминологию которая там?

Xintrea ★★★★★ ()
Ответ на: комментарий от Xintrea

Или ты настолько круто английский знаешь, что с лёту понимаешь стандарт и всю терминологию которая там?

Там технический англ, к нему за много лет привыкаешь.

А ты помнишь все, что в книжках написано, и работаешь не имея их под рукой?

Многое помню, потому что работаю с этим, а что непомню или не знаю - гуглю. Треды конечно тоже на лоре иногда создаю, но не прихожу в неописуемый шок от базовых вещей, вроде того как свич-кейс работает.

Dudraug ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.