|
Программирование >> Арифметические и логические операции
посредственно предназначенными для этого символами начала и конца комментария /* и */. Могу я объявить main как void, чтобы прекратились раздражающие сообщения main return no value ? (Я вызываю exit(), так что main ничего не возвращает) Нет. main должна быть объявлена как возвращающая int и использующая либо два, либо ни одного аргумента (подходящего типа). Если используется exit(), но предупреждающие сообщения не исчезают, вам нужно будет вставить лишний return, или использовать, если это возможно, директивы вроде notreached . Объявление функции как void просто не влияет на предупреждения компилятора; кроме того, это может породить другую последовательность вызова/возврата, несовместимую с тем, что ожидает вызывающая функция (в случае main это исполняющая система языка Си). В точности ли эквивалентен возврат статуса с помощью exit(status) возврату с помощью return? Формально, да, хотя несоответствия возникают в некоторых старых нестандартных системах, в тех случаях, когда данные, локальные для main(), могут потребоваться в процессе завершения выполнения (может быть при вызовах setbuf() или atexit()), или при рекурсивном вызове main(). Почему стандарт ANSI гарантирует только шесть значимых символов (при отсутствии различия между прописными и строчными символами) для внешних идентификаторов? Проблема в старых компоновщиках, которые не зависят ни от стандарта ANSI, ни от разработчиков компиляторов. Ограничение состоит в том, что только первые шесть символов значимы, а не в том, что длина идентификатора ограничена шестью символами. Это ограничение раздражает, но его нельзя считать невыносимым. В Стандарте оно помечено как выходящее из употребления , так что в следующих редакциях оно, вероятно, будет ослаблено. Эту уступку современным компоновщикам, ограничивающим количество значимых символов, обязательно нужно делать, не обращая внимания на бурные протесты некоторых программистов. (В Комментариях сказано, что сохранение этого ограничения было наиболее болезненным . Если вы не согласны или надеетесь с помощью какого-то трюка заставить компилятор, обремененный ограничивающим количество значимых символов компоновщиком, понимать большее количество этих символов, читайте превосходно написанный раздел 3.1.2 X3.159 Комментариев . Какая разница между memcpy и memmove? memmove гарантирует правильность операции копирования, если две области памяти перекрываются. memcpy не дает такой гарантии и, следовательно, может быть более эффективно реализована. В случае сомнений лучше применять memmove. Мой компилятор не транслирует простейшие тестовые программы, выдавая всевозможные сообщения об ошибках Видимо, ваш компилятор разработан до приема стандарта ANSI и поэтому не способен обрабатывать прототипы функций и тому подобное. Почему не определены некоторые подпрограммы из стандартной ANSI-библиотеки, хотя у меня ANSI совместимый компилятор? Нет ничего необычного в том, что компилятор, воспринимающий ANSI синтаксис, не имеет ANSI-совместимых головных файлов или стандартных библиотек. Почему компилятор Frobozz Magic C , о котором говорится, что он ANSI-совместимый, не транслирует мою программу? Я знаю, что текст подчиняется стандарту ANSI, потому что он транслируется компилятором gcc Практически все компиляторы (а gcc - более других) поддерживают некоторые нестандартные расширения. Уверены ли вы, что отвергнутый текст не применяет одно из таких расширений? Опасно экспериментировать с компилятором для исследования языка. Стандарт может допускать отклонения, а компилятор - работать неверно. Почему мне не удаются арифметические операции с указателем типа void *? Потому что компилятору не известен размер объекта, на который указывает void *. Перед арифметическими операциями используйте оператор приведения к типу (char *) или к тому типу, с которым собираетесь работать. Правильна ли запись a(3)= abc ? Что это значит? Эта запись верна в ANSI C (и, возможно, в некоторых более ранних компиляторах), хотя полезность такой записи сомнительна. Объявляется массив размера три, инициализируемый тремя буквами a, b и c без завершающего стринг символа \0. Массив, следовательно, не может использоваться как стринг функциями strcpy, printf %s и т.п. Что такое #pragma и где это может пригодиться? Директива #pragma обеспечивает особую, точно определенную лазейку для выполнения зависящих от реализации действий: контроль за листингом, упаковку структур, подавление предупреждающих сообщений (вроде комментариев /* NOTREACHED */ старой программы lint) и т.п. Что означает #pragma once ? Я нашел эту директиву в одном из головных файлов Это расширение, реализованное в некоторых препроцессорах, делает головной файл идемпотентным, т.е. эффект от однократного включения файла равен эффекту от многократного включения. Эта директива приводит к тому же результату, что и прием с использованием #ifndef. Вроде бы существует различие между зависимым от реализации, неописанным(unspecified) и неопределенным (undefined) поведением. В чем эта разница? Если говорить кратко, то при зависимом от реализации поведении необходимо выбрать один вариант и документировать его. При неописанном поведении также выбирается один из вариантов, но в этом случае нет необходимости это документировать. Неопределенное поведение означает, что может произойти все что угодно. Ни в одном из этих случаев Стандарт не выдвигает требований; в первых двух случаях Стандарт иногда предлагает (а может и требовать) выбор из нескольких близких вариантов поведения. Если вы заинтересованы в написании мобильных программ, можете игнорировать различия между этими тремя случаями, поскольку всех их необходимо будет избегать. Как написать макрос для обмена любых двух значений? На этот вопрос нет хорошего ответа. При обмене целых значений может быть использован хорошо известный трюк с использованием исключающего ИЛИ, но это не сработает для чисел с плавающей точкой или указателей. Не годится этот прием и в случае, когда оба числа - на самом деле одно и то же число. Из-за многих побочных эффектов не годится и очевидное суперкомпактное решение для целых чисел a=b=a=b. Когда макрос предназначен для переменных произвольного типа (обычно так и бывает), нельзя использовать временную переменную, поскольку не известен ее тип, а стандартный С не имеет оператора typeof. Если вы не хотите передавать тип переменной третьим параметров, то, возможно, наиболее гибким, универсальным решением будет отказ от использования макроса. У меня есть старая программа, которая пытается конструировать идентификаторы с помощью макроса #define Paste(a, b) a/**/b, но у меня это не работает То, что комментарий полностью исчезает, и, следовательно, может быть использован для склеивания соседних лексем (в частности, для создания новых идентификаторов), было недокументированной особенностью некоторых ранних реализаций препроцессора, среди которых заметна была реализация Рейзера (Reiser). Стандарт ANSI, как и K&R, утверждает, что комментарии заменяются единичными пробелами. Но поскольку необходимость склеивания лексем стала очевидной, стандарт ANSI ввел для этого специальный оператор ##, который может быть использован так: #define Paste(a, b) a##b Как наилучшим образом написать cpp макрос, в котором есть несколько инструкций? Обычно цель состоит в том, чтобы написать макрос, который не отличался бы по виду от функции. Это значит, что завершающая точка с запятой ставится тем, кто вызывает макрос, а в самом теле макроса ее нет. Тело макроса не может быть просто составной инструкцией, заключенной в фигурные скобки, поскольку возникнут сообщения об ошибке (очевидно, из-за лишней точки с запятой, стоящей после инструкции) в том случае, когда макрос вызывается после if, а в инструкции if/else имеется else-часть. Обычно эта проблема решается с помощью такого определения: #define Func() do { \ /* объявления */ \ что-то1; \ что-то2; \ */ \ } while(0) /* (нет завершающей ; ) */ Когда при вызове макроса добавляется точка с запятой, это расширение становится простой инструкцией вне зависимости от контекста. (Оптимизирующий компилятор удалит излишние проверки или переходы по условию 0, хотя lint это может и не принять.) Если требуется макрос, в котором нет деклараций или ветвлений, а все инструкции - простые выражения, то возможен другой подход, когда пишется одно, заключенное в круглые скобки выражение, использующее одну или несколько запятых. Такой подход позволяет также реализовать возврат значения). Можно ли в головной файл с помощью #include включить другой головной файл? Это вопрос стиля, и здесь возникают большие споры. Многие полагают, что вложенных с помощью #include файлов следует избегать: авторитетный Indian Hill Style Guide неодобрительно отзывается о таком стиле; становится труднее найти соответствующее определение; вложенные #include могут привести к сообщениям о многократном объявлении, если головной файл включен дважды; также затрудняется корректировка управляющего файла для утилиты Make. С другой стороны, становится возможным использовать модульный принцип при создании головных файлов (головной файл включает с помощью #include то, что необходимо только ему; в противном случае придется каждый раз использовать дополнительный #include, что способно вызвать постоянную головную боль); с помощью утилит, подобных grep (или файла tags) можно легко найти нужные определения вне зависимости от того, где они находятся, наконец, популярный прием: #ifndef HEADERUSED #define HEADERUSED ...содержимое головного файла... #endif делает головной файл идемпотентным , то есть такой файл можно безболезненно включать несколько раз; средства автоматической поддержки файлов для утилиты Make (без которых все равно не обойтись в случае больших проектов) легко обнаруживают зависимости при наличии вложенных #include. Работает ли оператор sizeof при использовании средства препроцессора #if? Нет. Препроцессор работает на ранней стадии компиляции, до того как становятся известны типы переменных. Попробуйте использовать константы, определенные в файле <limits.h>, предусмотренном ANSI, или сконфигурировать вместо этого командный файл. (А еще лучше написать программу, которая по самой своей природе нечувствительна к размерам переменных). Можно ли с помощью #if узнать, как организована память машины - по принципу: младший байт - меньший адрес или наоборот? Видимо, этого сделать нельзя. (Препроцессор использует для внутренних нужд только длинные целые и не имеет понятия об адресации). А уверены ли вы, что нужно точно знать тип организации памяти? Уж лучше написать программу, которая от этого не зависит. Во время компиляции мне необходимо сложное препроцесссирование, и я никак не могу придумать, как это сделать с помощью cpp cpp не задуман как универсальный препроцессор. Чем заставлять cpp делать что-то ему не свойственное, подумайте о написании небольшого специализированного препроцессора. Легко раздобыть утилиту типа make(1), которая автоматизирует этот процесс. Если вы пытаетесь препроцессировать что-то отличное от Си, воспользуйтесь универсальным препроцессором, (таким как m4). Мне попалась программа, в которой, на мой взгляд, слишком много директив препроцессора #ifdef. Как обработать текст, чтобы оставить только один вариант условной компиляции, без использования cpp, а также без раскрытия всех директив #include и #define? Свободно распространяются программы unifdef, rmifdef и scpp, которые делают в точности то, что вам нужно. Как получить список предопределенных идентификаторов? Стандартного способа не существует, хотя необходимость возникает часто. Если руководство по компилятору не содержит этих сведений, то, возможно, самый разумный путь - выделить текстовые строки из исполнимых файлов компилятора или препроцессора с помощью утилиты типа strings(1) системы Unix. Имейте в виду, что многие зависящие от системы предопределенные идентификаторы (например, unix ) нестандартны (поскольку конфликтуют с именами пользователя) и поэтому такие идентификаторы удаляются или меняются. Как написать cpp макрос с переменным количеством аргументов? Популярна такая уловка: определить макрос с одним аргументом, и вызывать его с двумя открывающими и двумя закрывающими круглыми скобками: #define DEBUG(args) (printf( DEBUG: ), printf args) if(n != 0) DEBUG(( n is %d\n , n));
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |