Неоднозначное поведение переменной в C

У меня есть следующий код

#include<stdio.h>
int main()
{
    int a12345678901234567890123456789012345;
    int a123456789012345678901234567890123456;
    int sum;

    scanf("%d",&a12345678901234567890123456789012345);
    scanf("%d",&a123456789012345678901234567890123456);
    sum = a12345678901234567890123456789012345 + a123456789012345678901234567890123456;
    printf("%dn",sum);

    return 0;
}

проблема в том, что мы знаем, что стандарт ANSI распознает переменные до 31 символа...но обе переменные одинаковы до 35 символов...но, тем не менее, программа компилируется без каких-либо ошибок и предупреждений и дает правильный вывод...
но как?
не должно ли это дать ошибку redeclaration?

5 ответов


многие компиляторы построены так, чтобы превышать спецификацию ANSI (например, при распознавании более 31 имени символьной переменной) в качестве защиты для программистов. Хотя он работает в используемом компиляторе, вы не можете рассчитывать на его работу только в любом компиляторе C...


[...] мы знаем, что стандарт ANSI распознает переменные до 31 символа [...] не должно ли это дать ошибку redeclaration?


на C89 обоснование развивает:

идентификаторы 3.1.2

в то время как реализация не обязана помнить больше, чем первый 31 символ идентификатора для сопоставления имени программисту фактически запрещено намеренно создавать два различные идентификаторы, которые одинаковы в первых 31 символах. Поэтому реализации могут хранить полный идентификатор; они не являются обязанный усечь до 31.

решение расширить значение до 31 символа для внутреннего имена были сделаны с небольшим сопротивлением, но решение сохранить старое шестизначное нечувствительное к регистру ограничение на значимость внешние имена были самыми болезненными. Хотя было высказано твердое мнение для того чтобы сделать C "правильным", требуя более длинных имен везде, Комитет признал, что эта формулировка должна быть сформулирована в предстоящие годы., сосуществовать с другими языками и со взрослыми ассемблеры и компоновщики. Вместо того чтобы подрывать поддержку стандарта, ограничения были сохранены.

компиляторы как GCC может хранить полный идентификатор.

  • количество значимых начальных символов в идентификаторе (C90 6.1.2, C90, C99 и C11 5.2.4.1, C99 и C11 6.4.2).

    для внутренних имен все символы имеют значение. Для внешних имена, количество значимые символы определяются компоновщиком; почти для всех целей важны все персонажи.


соответствующая реализация должна поддерживать по крайней мере 31 символ для внешнего идентификатора (и ваши идентификаторы являются внутренними, где предел 63 для C99 и C11).

фактически, наличие всех значимых символов является целью стандарта, но комитет не хочет делать реализации несоответствующими, не предоставляя его. Ограничения для внешних идентификаторов исходят от некоторых компоновщиков, которые не могут предоставить больше (в C89 было только 6 символов требуется быть значительным, поэтому старые стандартные библиотечные функции имеют имена не длиннее 6 символов).

чтобы быть точным, стандарт точно не санкционирует эти ограничения, язык в стандарте довольно разрешительный:

C11 (n1570) 5.2.4.1 лимиты переводов

реализация должна быть способна перевести и выполнить по крайней мере одну программу, которая содержит по крайней мере один экземпляр каждого из следующих пределы:18)

  • [...]
  • 63 значимых начальных символа во внутреннем идентификаторе или имени макроса (каждое универсальное имя символа или расширенный исходный символ считается одним символом)
  • 31 значимые начальные символы во внешнем идентификаторе (каждое универсальное имя символа, указывающее короткий идентификатор 0000FFFF или меньше, считается 6 символов, каждое универсальное имя символа, указывающее короткий идентификатором 00010000 и более считается 10 символов, а каждый расширенный исходный символ считается таким же количеством символов, как и соответствующее универсальное имя символа, если таковое имеется)19)
  • [...]

сноска 18) ясно выражает намерение:

реализации должны избегать введения фиксированных ограничений перевода, когда это возможно.

сноска 19) относится к будущие направления язык 6.11.3:

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

и объяснить вседозволенность в первом предложении пункта 5.2.4.1, см. обоснование C99 (5.10)

5.2.4 экологические пределы

комитет C89 согласился с тем, что в стандарте должно быть что-то сказано об определенных возможностях и ограничениях, но вопрос о том, как обеспечить соблюдение этих договорных положений, был предметом значительных дебатов.

5.2.4.1 лимиты переводов

стандарт требует, чтобы реализация была в состоянии перевести и выполнить некоторую программу, которая соответствует каждому из указанных пределов. Этот критерий ощущалось дать полезная широта для исполнителя при выполнении этих ограничений. В то время как недостаточная реализация, вероятно, могла бы создать программу, отвечающую этому требованию, но все же преуспеть в бесполезности, комитет C89 считал, что такая изобретательность, вероятно, потребует больше работы, чем что-то полезное. Смысл обоих комитетов C89 и C99 заключался в том, что исполнители не должны толковать пределы перевода как значения жестких параметров, а скорее как набор критериев, по которым будет дана оценка реализации.


нет предела . На самом деле есть предел , он должен быть достаточно мал, чтобы поместиться в памяти, но иначе нет . Если есть встроенный предел (я не верю, что есть), он настолько огромен, что вам будет очень трудно его достичь. Я сгенерированный код C++ с 2 переменными с различным последним символом, чтобы гарантировать, что имена, которые долго различны . Я добрался до файла 64KB и подумал, что этого достаточно.