2015-05-31 1 views
25

Следующая программа печатает один и тот же номер дважды на GCC 4.8.2:В скобках есть разница при определении размера массива?

#include <stdio.h> 

int main() 
{ 
    char a[13]; 
    printf("sizeof a is %zu\n", sizeof a); 
    printf("sizeof(a) is %zu\n", sizeof(a)); 
} 

Согласно this reddit post, НКУ не являются стандартным совместимым в этом отношении, потому что выражение в скобках не в списке исключений для того, когда размытие между матрицами и указателями не происходит.

Этот парень прав? Вот соответствующая стандартная цитата:

исключением случаев, когда это операнд sizeof оператора или одноместной & оператора, или строку символов буквального, используемый для инициализации массива символьного типа, или широкий строковый литерал используется для инициализации массива с типом элемента, совместимым с wchar_t, значение lvalue, которое имеет тип «массив типа», преобразуется в выражение, которое имеет тип «указатель на тип», который указывает на начальный элемент объекта массива и не является значением lvalue ,

Просто чтобы быть ясно, что он утверждает, что (a) должен вызвать массив в указатель-распад, потому что круглые скобки не рассматриваются в списке выше (sizeof оператора, одноместной & оператора, строковый литерал, как инициализаторе).

+7

Нет, этот парень серьезно запутался –

+1

По его словам, я бы согласился с * terminally confused * – chqrlie

+1

Я не занимался этим этим материалом около 15 лет, но я определенно вспоминаю сценарий с, я думаю , 'sizeof', где наличие или отсутствие круглых скобок было значительным, - определяется, если вы принимаете размер указателя или размер элемента, или что-то в этом роде. –

ответ

24

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

Обычно считается, что ((void*)0) технически не является константой нулевого указателя, поскольку нет правила, согласно которому константа нулевого указателя в скобках является константой нулевого указателя.

Некоторые компиляторы выдают ошибку для char s[] = ("abc");, поскольку, поскольку массив символов может быть инициализирован из строкового литерала, это правило не распространяется на строковые литералы в скобках.

Существует много подобных примеров. Вы нашли одного из них.

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

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

+1

Достаточно плохо, что нельзя просто проверить, относится ли идентификатор к указателю или массиву, создавая 'sizeof (argv)' склонность к ошибкам. Было бы еще хуже, если бы «sizeof (argv)» и «sizeof argv» оценивались по другому. В действительности необходим оператор 'countof (a)', который вычисляет количество элементов массива и выдает ошибку времени компиляции при применении к не-массиву. – chqrlie

+0

@chqrlie Я бы предпочел иметь строительные блоки, необходимые для создания 'countof' (я обычно видел его с именем' LENGTHOF', но либо работает). С C11 '_Generic', все, что отсутствует, я думаю, что-то вроде' decltype' C++ 11. Если бы у нас это было, мы могли бы статически проверить, что тип 'argv' отличается от' & * argv'. – hvd

+0

Я нахожу 'LENGTHOF (a)' менее привлекательным из-за потенциальной путаницы между длиной строки и размером соответствующего массива байтов. Я согласен с тем, что инструментов будет достаточно, например: typeof (a)! = Typeof (& * (a)) ' – chqrlie

21

С C99, 6.5.1, на выражения в скобках:

Его тип и значение идентичны таковым из выражения в скобки,.

На первый взгляд, может показаться, что это противоречит со списком исключений вы имеете в виду (6.3.2.1):

исключением случаев, когда это операнд sizeof оператора или одинарный & оператор, или строковый литерал используется для инициализации массива, выражение, которое имеет тип «массив типа» преобразуется в выражение с типом «указатель на тип» ...

Однако этот список в контексте операторов/операндов; скобки не считаются оператором (на основе категоризации, подразумеваемой структурой раздела 6.5).

+0

Вы можете перейти прямо в раздел, благодаря некоторой смелой душе, которая много часов переводила документ pdf в html: http://www.iso-9899.info/n1256.html#6.5.1p5, http: // www. iso-9899.info/n1256.html#6.3.2.1p3 ... или для C11: http://www.iso-9899.info/n1570.html#6.5.1p5, http: //www.iso-9899 .info/n1570.html # 6.3.2.1p3 – Sebivor

+1

C11, по-видимому, разрешает _type-name_ только в партизированной версии (6.5.3 # 1). В связи с этим версия с круглыми скобками вокруг _unary-expression_ синтаксически была бы несанкционированной версией, причем скобка была частью _unary-expression_. Делает работу компилятора не проще. Изменить: то же самое для C99. – Olaf

 Смежные вопросы

  • Нет связанных вопросов^_^