Error statement with no effect

cc1: warnings being treated as errors when compile FreeBSD 8.2 Release I am trying to compile FreeBsd 8.2 RELEASE kernel Build the kernel . it compiles until I get this error . I am not sure how to assess this error message and fix it. Any recommended directions? UPDATE TRIED ON ANOTHER VM Got […]

Содержание

  1. cc1: warnings being treated as errors when compile FreeBSD 8.2 Release
  2. UPDATE TRIED ON ANOTHER VM
  3. 1 Answer 1
  4. Помоги компилятору помочь тебе
  5. Предисловие
  6. Содержание
  7. Ода компилятору
  8. Игнорировать нельзя исправить
  9. -Waddress
  10. -Warray-bounds=1
  11. -Wbool-compare
  12. -Wbool-operation
  13. -Wcatch-value
  14. -Wchar-subscripts
  15. -Wcomment
  16. -Wint-in-bool-context
  17. -Winit-self
  18. -Wlogical-not-parentheses
  19. -Wmaybe-uninitialized
  20. -Wmemset-elt-size
  21. -Wmemset-transposed-args
  22. -Wmisleading-indentation
  23. -Wmissing-attributes
  24. -Wmultistatement-macros
  25. -Wnonnull
  26. -Wnonnull-compare
  27. -Wparentheses
  28. -Wpessimizing-move
  29. -Wreorder
  30. -Wreturn-type
  31. -Wsequence-point
  32. -Wsign-compare
  33. -Wsizeof-pointer-div
  34. -Wsizeof-pointer-memaccess
  35. -Wstrict-aliasing
  36. -Wswitch
  37. -Wtautological-compare
  38. -Wtrigraphs
  39. -Wuninitialized
  40. -Wunused-function
  41. -Wunused-variable
  42. -Wextra
  43. -Wempty-body
  44. -Wimplicit-fallthrough
  45. -Wmissing-field-initializers
  46. -Wredundant-move
  47. -Wtype-limits
  48. -Wshift-negative-value
  49. -Wunused-parameter
  50. -Wunused-but-set-parameter
  51. -Wpedantic
  52. Нужно больше предупреждений
  53. -Wctor-dtor-privacy
  54. -Wnon-virtual-dtor
  55. -Wold-style-cast
  56. -Woverloaded-virtual
  57. -Wsign-promo
  58. -Wduplicated-branches
  59. -Wduplicated-cond
  60. -Wfloat-equal
  61. -Wshadow=compatible-local
  62. -Wcast-qual
  63. -Wconversion
  64. -Wzero-as-null-pointer-constant
  65. -Wextra-semi
  66. -Wsign-conversion
  67. -Wlogical-op
  68. -Werror
  69. Заключение

cc1: warnings being treated as errors when compile FreeBSD 8.2 Release

I am trying to compile FreeBsd 8.2 RELEASE kernel

Build the kernel

. it compiles until I get this error .

I am not sure how to assess this error message and fix it.

Any recommended directions?

UPDATE TRIED ON ANOTHER VM

Got a similar error message

1 Answer 1

In both cases those are not primarily warnings that break the build.

For the kernel compilation:

the compiler tells you, that the code is trying to access something that isn’t there. This may have many reasons, but generally it suggests that the code is broken. Maybe you are trying to compile a module that relies on newer/older internal kernel API (i.e. is using another definition of structures than the rest of the kernel).

is often either a programming mistake (i.e. indeed passing something else as argument than what is expected) or a missing cast operator.

is caused by -Werror in the compiler flags, which tells the compiler to treat warnings as errors. Which is usually a Good Idea TM , actually (mostly because of the often encountered — «But it compiles, there are just some warnings» attitude).

For the other problem:

is actually an error from the linker — compilation went (more or less) well but you are not supplying external libraries that provide some symbols referenced by the code. This often happens when you correctly #include header files and then forget to tell linker to actually link against that library (usually the -l option).

Источник

Помоги компилятору помочь тебе

Предисловие

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

Огромное количество претензий, которые предъявляют к языку C++ в этих ваших интернетах, — про сложность, небезопасность, стрельбу по ногам и т.п., — относятся как раз к тем случаям, когда люди просто не знают о том, что можно решить эти проблемы лёгким движением пальцев по клавиатуре.

Давайте же исправим эту вопиющую несправедливость, и прольём свет истины на возможности компилятора по предотвращению ошибок.

Содержание

Ода компилятору

Компилятор – лучший друг плюсовика. Компилятор — это не просто транслятор формального человекочитаемого языка в машинные коды. Компилятор — лучший помощник в написании программ.

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

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

Игнорировать нельзя исправить

Большинство предупреждений — это не «бзик» компилятора, который можно просто проигнорировать. Предупреждение — это потенциальная ошибка. Предупреждение — это сигнал от компилятора о том, что написано одно, а требуется, возможно, что-то совершенно иное.

Поэтому программист должен помочь компилятору понять, как трактовать спорную ситуацию. То есть либо поправить свою ошибку, либо сообщить компилятору явно о том, что нужно верить программисту и делать именно то, что написано. Причём это поможет не только компилятору, но и человеку, который будет читать код. Лишний static_cast или пара скобок будут явно свидетельствовать о том, что имелось в виду именно то, что написано.

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

Надеюсь, что данное не слишком занимательное чтиво поможет правильно поставить запятую в заголовке этого раздела.

Сразу хочу оговориться, что далее речь пойдёт исключительно о языке C++ и компиляторе GCC (впрочем, подавляющая часть информации актуальна и для компилятора Clang). Информацию о других компиляторах и языках придётся искать в соответствующих справочниках.

-Wall — это «агрегатор» базовых предупреждений. В языке C++ он включает в себя длинный перечень предупреждений, каждое из которых будет рассмотрено отдельно (на самом деле, рассмотрены будут не все, а только те, которые непосредственно помогают выявлять ошибки).

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

-Waddress

Предупреждает о странной работе с адресами. Например, об использовании адреса функции в условном выражении. Такое может произойти, если забыть поставить скобки после имени функции:

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

-Warray-bounds=1

Предупреждает о выходе за пределы массивов. Используется только вместе с -O2 .

-Wbool-compare

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

-Wbool-operation

Предупреждает о подозрительных операциях с булевыми выражениями. Например, о побитовом отрицании:

Что касается инкрементов и декрементов булевых переменных, то в C++17 это просто ошибки, безо всяких предупреждений.

-Wcatch-value

Предупреждает о обработчиках исключений, которые принимают полиморфные объекты по значению:

Есть и более сильные версии предупреждения: -Wcatch-value=n (см. справку к компилятору).

-Wchar-subscripts

Предупреждает об обращении к массиву по индексу, тип которого char . А ведь char является знаковым на многих машинах:

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

-Wint-in-bool-context

Предупреждает о подозрительном использовании целых чисел там, где ожидаются булевы выражения, например, в условных выражениях:

Другой пример — операции побитового сдвига в булевом контексте. Вполне вероятно, что здесь произошла опечатка, и имелся в виду не сдвиг, а сравнение:

А также сообщает о любых видах умножения в булевом контексте.

-Winit-self

Предупреждает об инициализации переменных самими сабями. Используется только вместе с флагом -Wuninitialized .

-Wlogical-not-parentheses

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

Используется для того, чтобы отлавливать подозрительные конструкции вроде следующей:

Традиционный способ сообщить компилятору, что так и было задумано — поставить скобки, о чём и сообщает компилятор.

-Wmaybe-uninitialized

Предупреждает о том, что существует возможность использования непроинициализированной переменной.

В данном конкретном случае решается с помощью конструкции default :

-Wmemset-elt-size

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

-Wmemset-transposed-args

Предупреждает о том, что пользователь, вероятно, перепутал порядок аргументов в функции memset :

-Wmisleading-indentation

Предупреждает о том, что отступы в коде не отражают структуру этого кода. Особенно это актуально для конструкций if , else , while и for . Пример:

-Wmissing-attributes

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

-Wmultistatement-macros

Предупреждает о макросах, состоящих из нескольких инструкций, и используемых в выражениях if , else , while и for . В такой ситуации под действие выражений попадает только первая инструкция макроса, и это, вероятно, ошибка:

-Wnonnull

Предупреждает о передаче нулевого указателя в функцию, аргументы которой помечены атрибутом nonnull .

-Wnonnull-compare

Предупреждает о сравнении с нулём аргумента функции, помеченного атрибутом nonnull .

-Wparentheses

Типичный случай — опечатались, и вместо равенства написали присвоение:

Компилятор, естественно, сомневается:

Либо исправляем код, либо убеждаем компилятор в том, что мы хотели именно присвоение:

-Wpessimizing-move

Иногда явная попытка переноса может ухудшить производительность. Пример:

-Wreorder

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

-Wreturn-type

Предупреждает о том, что из функции не вернули заявленный результат:

-Wsequence-point

Сообщает о подозрительных операциях относительно точек следования. Любимый пример (никогда так не делайте):

-Wsign-compare

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

-Wsizeof-pointer-div

Предупреждает о подозрительном делении друг на друга двух результатов выражения sizeof , когда размер указателя делится на размер объекта. Обычно это бывает, когда пытаются вычислить размер массива, но вместо массива по ошибке берут указатель:

-Wsizeof-pointer-memaccess

Предупреждает о подозрительных параметрах, передаваемых в строковые функции и функции для работы с памятью ( str. , mem. и т.п.), и использующих оператор sizeof . Например:

-Wstrict-aliasing

Каламбур типизации (strict aliasing) — это отдельная большая тема для разговора. Предлагаю читателю найти литературу по этой теме самостоятельно.

В общем, это тоже крайне полезное предупреждение.

-Wswitch

Предупреждает о том, что не все элементы перечисления задействованы в конструкции switch :

-Wtautological-compare

Предупреждает о бессмысленном сравнении переменной с самой собой:

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

-Wtrigraphs

Предупреждает о наличии триграфов, которые могут изменить смысл программы. Не сообщается о триграфах в теле комментария, за исключением случаев, когда триграф трактуется как перевод строки.

-Wuninitialized

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

-Wunused-function

Предупреждает о том, что статическая функция объявлена, но не определена, либо о том, что статическая функция, не помеченная как inline , не используется.

-Wunused-variable

Предупреждает о том, что переменная не используется.

Для того, чтобы помочь компилятору понять, что так и задумывалось, можно использовать конструкцию static_cast (. ) :

«Агрегатор» дополнительных предупреждений. Включает много интересного, чего нет в -Wall (как и в случае с -Wall , рассмотрены будут не все возможности).

-Wempty-body

Предупреждает о пустом теле условных выражений или цикла do-while . Чаще всего это говорит об опечатке, меняющей логику программы:

-Wimplicit-fallthrough

Предупреждает о «проваливании» в операторе switch :

Компилятор предполагает, что программист забыл break , и case 2 не должен проваливаться:

В C++17 для обозначения явного намерения появился специальный атрибут — fallthrough :

-Wmissing-field-initializers

Предупреждает о том, что отдельные члены структуры не были проинициализированы. Скорее всего это просто забыли сделать:

-Wredundant-move

Предупреждает о ненужном вызове std::move в случаях, когда компилятор сам сделает всё, что нужно:

-Wtype-limits

Предупреждает о сравнениях, которые всегда имеют один и тот же результат. Например, когда беззнаковое число проверяется на неотрицательность. Если программист делает такую проверку, то, видимо, предполагает, что число в теории может быть отрицательным, однако, это не так. Видимо, он где-то ошибся:

-Wshift-negative-value

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

-Wunused-parameter

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

В C++17 для явного выражения намерения существует атрибут maybe_unused :

-Wunused-but-set-parameter

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

-Wpedantic

-Wall и -Wextra — это не всё, на что способен компилятор.

В дополнение к ним существует флаг -Wpedantic (он же -pedantic ), который проверяет соответствие кода стандарту ISO C++, сообщает об использовании запрещённых расширений, о наличии лишних точек с запятой, нехватке переноса строки в конце файла и прочих полезных штуках.

Нужно больше предупреждений

Но и это ещё не всё. Есть несколько флагов, которые почему-то не входят ни в один из «аргегаторов», но крайне важны и полезны.

-Wctor-dtor-privacy

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

Аналогично, сообщает, что у класса есть закрытые функции-члены, а открытых нет ни одной.

-Wnon-virtual-dtor

Предупреждает о том, что у класса есть виртуальные функции-члены, но деструктор при этом не виртуальный. Очень сложно представить себе такой класс. Вероятнее всего, это ошибка.

-Wold-style-cast

Предупреждает о приведении типов в стиле языка C. В плюсах есть прекрасные и ужасные static_cast , dynamic_cast , reinterpret_cast и const_cast , которые более локальны и более описательны. Сишный способ слишком сильный и — о, ужас, — небезопасный. Лучше его не использовать вообще.

-Woverloaded-virtual

Предупреждает о попытке в классе-наследнике перегрузить виртуальную функцию базового класса:

-Wsign-promo

Крайне полезный флаг. Предупреждает о неочевидном выборе перегруженной функции:

Вероятнее всего, хотели-таки позвать вторую перегрузку, а не первую. А если всё-таки первую, то будьте любезны сказать об этом явно.

-Wduplicated-branches

Предупреждает о том, что ветви if и else одинаковы:

Условный оператор ?: также под прицелом:

Для меня абсолютная загадка, почему этот флаг не включён не то, что в -Wall , а вообще по умолчанию.

-Wduplicated-cond

Предупреждает об одинаковых условиях в цепочках if-else-if :

-Wfloat-equal

Предупреждает о проверке на равенство между двумя числами с плавающей точкой. Скорее всего, это ошибка, и сравнение нужно проводить с заданной точностью.

Если же требуется именно сравнить на равенство (такое редко, но бывает), то можно использовать std::equal_to , который под предупреждение не попадает.

-Wshadow=compatible-local

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

-Wcast-qual

Предупреждает о преобразовании указателя, при котором сбрасываются квалификаторы. Например, чтобы случайно не потерять const .

-Wconversion

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

Если вы раньше никогда не включали этот флаг, то будет интересно.

-Wzero-as-null-pointer-constant

Предупреждает об использовании целочисленного нуля вместо nullptr .

Флаг для педантов. Сообщает о лишней точке с запятой после определения функции-члена.

-Wsign-conversion

Как и -Wconversion помогает предотвратить большое количество неявных преобразований, которые запросто могут быть ошибками:

-Wlogical-op

Предупреждает о подозрительных логических выражениях. Например, когда вместо побитового «И» поставили логическое «И», или логическое выражение имеет одинаковые операнды:

-Werror

С этого, вообще говоря, стоило бы начать. Данный флаг делает все предупреждения ошибками. Код не скомпилируется при наличии хотя бы одного предупреждения.

Без этого флага всё остальное имеет мало смысла. Но если понять и принять мысль о том, что предупреждение — это что-то подозрительное, и их быть не должно, то именно этот флаг и позволит поддерживать код в чистоте.

В дополнение к -Werror существует флаг -pedantic-errors , который не эквивалентен комбинации -Wpedantic -Werror .

Заключение

Резюмируя, для компилятора GCC (Clang кое-что из этого не умеет, к сожалению) я рекомендую включать следующий минимальный набор флагов, по необходимости дополняя его более сложными диагностиками.

Да, такой список флагов может породить большое количество ошибок, которые поначалу могут показаться излишними. Но явное лучше неявного. Если знаешь, что делаешь — делай. Но делай это так, чтобы всем было понятно, что именно так ты и хотел. Поработав таким образом хотя бы неделю, вы поймёте, насколько это прекрасно, и уже не сможете вернуться обратно.

Любите ваш компилятор и помогайте ему помогать вам писать программы.

Источник

_SayHello

873 / 534 / 175

Регистрация: 30.07.2015

Сообщений: 1,739

1

10.03.2017, 12:34. Показов 4948. Ответов 7

Метки нет (Все метки)


Подскажите пожалуйста, написал функцию которая выводит строку на дисплей. В связи с тем что русская кодировка не совпадает с ascii пришлось под русский писать самостоятельно. В функцию я передаю адрес первого элемента и вывожу до окончания строки. Вот кусок функции, всю не привожу, уж больно длинная, но принцип прост и понятен:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void PrintStrFromMB(char* Text)
{
    for(Text; *Text; Text++)
    {
        switch(*Text)
        {
            case 'А':
            {
                SendByte(0b01000001, 1);
                break;
            }
            case 'Б':
            {
                SendByte(0b10100000, 1);
                break;
            }
            case 'В':
            {
                SendByte(0b01000010, 1);
                break;
            }
            case 'Г':
            {
                SendByte(0b10100001, 1);
                break;
            }
            case 'Д':
            {
                SendByte(0b11100000, 1);
                break;
            ...
            }

При компиляции выдает warning: statement with no effect. Все шуршит и работает, но глаза мозолит.



0



1786 / 1036 / 445

Регистрация: 12.05.2016

Сообщений: 2,550

10.03.2017, 12:48

2

Лучший ответ Сообщение было отмечено _SayHello как решение

Решение

Цитата
Сообщение от _SayHelli
Посмотреть сообщение

for(Text; *Text; Text++)

Это зачем?



1



873 / 534 / 175

Регистрация: 30.07.2015

Сообщений: 1,739

10.03.2017, 12:52

 [ТС]

3

shvyrevvg, понял, видимо надо залезть в Кернигана, перечитать про for. Не люблю оставлять пустые ; Спасибо, буду знать.



0



1786 / 1036 / 445

Регистрация: 12.05.2016

Сообщений: 2,550

10.03.2017, 12:59

4

Цитата
Сообщение от _SayHelli
Посмотреть сообщение

Не люблю оставлять пустые ;

Как вариант while().



0



_SayHello

873 / 534 / 175

Регистрация: 30.07.2015

Сообщений: 1,739

10.03.2017, 13:12

 [ТС]

5

shvyrevvg, да можно было и так

C++
1
while(*(Text++))



0



TheCalligrapher

Вездепух

Эксперт CЭксперт С++

10435 / 5704 / 1553

Регистрация: 18.10.2014

Сообщений: 14,101

10.03.2017, 21:22

6

Цитата
Сообщение от _SayHelli
Посмотреть сообщение

shvyrevvg, да можно было и так

C++
1
while(*(Text++))

Можно много как, но это не эквивалент оригинального for.



0



1786 / 1036 / 445

Регистрация: 12.05.2016

Сообщений: 2,550

10.03.2017, 21:34

7

Цитата
Сообщение от TheCalligrapher
Посмотреть сообщение

Можно много как, но это не эквивалент оригинального for.

TheCalligrapher, а подробнее можете рассказать? Дело в семантике?



0



Вездепух

Эксперт CЭксперт С++

10435 / 5704 / 1553

Регистрация: 18.10.2014

Сообщений: 14,101

10.03.2017, 22:00

8

Цитата
Сообщение от shvyrevvg
Посмотреть сообщение

TheCalligrapher, а подробнее можете рассказать? Дело в семантике?

Хм… Я имел в виду лишь очевидное: такой while увеличит значение Text до тела цикла, в то время как оригинальный for увеличивает значение Text после тела цикла.



0



GCC — GNU Compiler Collection — набор компиляторов и сопутствующих утилит, разработанный в рамках движения GNU. GCC один из старейших Open Source проектов, первый релиз состоялся в 1985 году, автор сам Ричард Столлман. В исходном варианте поддерживал только язык C и аббревиатура GCC расшифровывалась как GNU C Compiler. Постепенно набор доступных языков расширялся, были добавлены компиляторы Fortran, C++, Ada. С уверенностью можно сказать, что современный мир Open Source обязан своим рождением GCC (по крайней мере без GCC он был бы другим). В настоящее время проект находиться под крылом Free Software Foundation. GCC выпускается под лицензией GPLv3 и является стандартным компилятором для большинства свободных UNIX-подобных операционных систем. В базовый набор входят компиляторы языков: C, C++, Objective-C, Java, Fortran, Ada. GCC поддерживает все основные процессорные архитектуры. Официальный сайт проекта gcc.gnu.org

Основы

GCC входит в состав любого дистрибутива Linux и, как правило, устанавливается по умолчанию. Интерфейс GCC, это стандартный интерфейс компилятора на UNIX платформе, уходящий своими корнями в конец 60-х, начало 70-х годов прошлого века — интерфейс командной строки. Не стоит пугаться, за прошедшее время механизм взаимодействия с пользователем был отточен до возможного в данном случае совершенства, и работать с GCC (при наличии нескольких дополнительных утилит и путного текстового редактора) проще, чем с любой из современных визуальных IDE. Авторы набора постарались максимально автоматизировать процесс компиляции и сборки приложений. Пользователь вызывает управляющую программу gcc, она интерпретирует переданные аргументы командной строки (опции и имена файлов) и для каждого входного файла, в соответствии с использованным языком программирования, запускает свой компилятор, затем, если это необходимо, gcc автоматически вызывает ассемблер и линковщик (компоновщик).

Любопытно, компиляторы одни из немногих приложений UNIX для которых не безразлично расширение файлов. По расширению GCC определяет что за файл перед ним и, что с ним нужно (можно) сделать. Файлы исходного кода на языке C должны иметь расширение .c, на языке C++, как вариант, .cpp, заголовочные файлы на языке C .h, объектные файлы .o и так далее. Если использовать неправильное расширение, gcc будет работать не корректно (если вообще согласиться, что-либо делать).

Перейдём к практике. Напишем, откомпилируем и исполним какую-нибудь незамысловатую программу. Не будем оригинальничать, в качестве исходного файла примера программы на языке C сотворим файл с вот таким содержимым:

/* hello.c */

#include <stdio.h>

main(void)
{

        printf("Hello Worldn");

        return 0;

}

Теперь в каталоге c hello.c отдадим команду:

$ gcc hello.c

Через несколько долей секунды в каталоге появиться файл a.out:

$ ls
a.out hello.c

Это и есть готовый исполняемый файл нашей программы. По умолчанию gcc присваивает выходному исполняемому файлу имя a.out (когда-то очень давно это имя означало assembler output).

Запустим получившийся программный продукт:

$ ./a.out
Hello World

Почему в команде запуска на исполнение файла из текущего каталога необходимо явно указывать путь к файлу? Если путь к исполняемому файлу не указан явно, оболочка, интерпретируя команды, ищет файл в каталогах, список которых задан системной переменной PATH.

$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

Каталоги в списке разделены символом двоеточия. При поиске файлов, оболочка просматривает каталоги в том порядке, в котором они перечислены в списке. По умолчанию, из соображений безопасности, текущий каталог . в список не внесен, соответственно, оболочка исполняемые файлы искать в нем не будет.

Почему не рекомендуется вносить . в PATH? Считается, что в реальной многопользовательской системе всегда найдется какой-нибудь нехороший человек, который разместит в общедоступном каталоге вредоносную программу с именем исполняемого файла, совпадающим с именем какой-нибудь команды, часто вызываемой местным администратором с правами суперпользователя… Заговор удастся если . стоит в начале списка каталогов.

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

$ file hello.c
hello.c: ASCII C program text
$ file annotation.doc
annotation.doc: CDF V2 Document, Little Endian, Os: Windows, Version 5.1, Code page: 1251, Author: MIH, Template: Normal.dot, Last Saved By: MIH, Revision Number: 83, Name of Creating Application: Microsoft Office Word, Total Editing Time: 09:37:00, Last Printed: Thu Jan 22 07:31:00 2009, Create Time/Date: Mon Jan 12 07:36:00 2009, Last Saved Time/Date: Thu Jan 22 07:34:00 2009, Number of Pages: 1, Number of Words: 3094, Number of Characters: 17637, Security: 0

Вот собственно и всё, что требуется от пользователя для успешного применения gcc :)

Имя выходного исполняемого файла (как впрочем и любого другого файла формируемого gcc) можно изменить с помощью опции -o:

$ gcc -o hello hello.c
$ ls
hello hello.c
$ ./hello
Hello World

В нашем примере функция main() возвращает казалось бы ни кому не нужное значение 0. В UNIX-подобных системах, по завершении работы программы, принято возвращать в командную оболочку целое число — в случае успешного завершения ноль, любое другое в противном случае. Интерпретатор оболочки автоматически присвоит полученное значение переменной среды с именем ?. Просмотреть её содержимое можно с помощью команды echo $?:

$ ./hello
Hello World
$ echo $?
0

Выше было сказано, что gcc это управляющая программа, предназначенная для автоматизации процесса компиляции. Посмотрим что же на самом деле происходит в результате исполнения команды gcc hello.c.

Процесс компиляции можно разбить на 4 основных этапа: обработка препроцессором, собственно компиляция, ассемблирование, линковка (связывание).

Опции gcc позволяют прервать процесс на любом из этих этапов.

Препроцессор осуществляет подготовку исходного файла к компиляции — вырезает комментарии, добавляет содержимое заголовочных файлов (директива препроцессора #include), реализует раскрытие макросов (символических констант, директива препроцессора #define).

Воспользовавшись опцией -E дальнейшие действия gcc можно прервать и просмотреть содержимое файла, обработанного препроцессором.

$ gcc -E -o hello.i hello.c
$ ls
hello.c  hello.i
$ less hello.i
. . .
# 1 "/usr/include/stdio.h" 1 3 4
# 28 "/usr/include/stdio.h" 3 4
# 1 "/usr/include/features.h" 1 3 4
. . .
typedef unsigned char __u_char;
typedef unsigned short int __u_short;
typedef unsigned int __u_int;
. . .
extern int printf (__const char *__restrict __format, ...);
. . .
# 4 "hello.c" 2
 
main (void)
{
 
 printf ("Hello Worldn");
 
 return 0;
 
}

После обработки препроцессором исходный текст нашей программы разбух и приобрел не удобочитаемый вид. Код, который мы когда-то собственноручно набили, свелся к нескольким строчкам в самом конце файла. Причина — подключение заголовочного файла стандартной библиотеки C. Заголовочный файл stdio.h сам по себе содержит много всего разного да ещё требует включения других заголовочных файлов.

Обратите внимание на расширение файла hello.i. По соглашениям gcc расширение .i соответствует файлам с исходным кодом на языке C не требующим обработки препроцессором. Такие файлы компилируются минуя препроцессор:

$ gcc -o hello hello.i
$ ls
hello hello.c hello.i
$ ./hello
Hello World

После препроцессинга наступает очередь компиляции. Компилятор преобразует исходный текст программы на языке высокого уровня в код на языке ассемблера.

Значение слова компиляция размыто. Википедисты, например, считают, ссылаясь на международные стандарты, что компиляция это «преобразование программой-компилятором исходного текста какой-либо программы, написанного на языке программирования высокого уровня, в язык, близкий к машинному, или в объектный код.» В принципе это определение нам подходит, язык ассемблера действительно ближе к машинному, чем C. Но в обыденной жизни под компиляцией чаще всего понимают просто любую операцию, преобразующую исходный код программы на каком-либо языке программирования в исполняемый код. То есть процесс, включающий все четыре означенных выше, этапа также может быть назван компиляцией. Подобная неоднозначность присутствует и в настоящем тексте. С другой стороны, операцию преобразования исходного текста программы в код на языке ассемблера можно обозначить и словом трансляция — «преобразование программы, представленной на одном из языков программирования, в программу на другом языке и, в определённом смысле, равносильную первой».

Остановить процесс создания исполняемого файла по завершении компиляции позволяет опция -S:

$ gcc -S hello.c
$ ls
hello.c  hello.s
$ file hello.s
hello.s: ASCII assembler program text
$ less hello.s
        .file   "hello.c"
        .section        .rodata
.LC0:
        .string "Hello World"
        .text
.globl main
        .type   main, @function
main:
        pushl   %ebp
        movl    %esp, %ebp
        andl    $-16, %esp
        subl    $16, %esp
        movl    $.LC0, (%esp)
        call    puts
        movl    $0, %eax
        leave
        ret
        .size   main, .-main
        .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
        .section        .note.GNU-stack,"",@progbits

В каталоге появился файл hello.s, содержащий реализацию программы на языке ассемблера. Обратите внимание, задавать имя выходного файла с помощью опции -o в данном случае не потребовалось, gcc автоматически его сгенерировал, заменив в имени исходного файла расширение .c на .s. Для большинства основных операций gcc имя выходного файла формируется путем подобной замены. Расширение .s стандартное для файлов с исходным кодом на языке ассемблера.

Получить исполняемый код разумеется можно и из файла hello.s:

$ gcc -o hello hello.s
$ ls
hello hello.c hello.s
$ ./hello
Hello World

Следующий этап операция ассмеблирования — трансляция кода на языке ассемблера в машинный код. Результат операции — объектный файл. Объектный файл содержит блоки готового к исполнению машинного кода, блоки данных, а также список определенных в файле функций и внешних переменных (таблицу символов), но при этом в нем не заданы абсолютные адреса ссылок на функции и данные. Объектный файл не может быть запущен на исполнение непосредственно, но в дальнейшем (на этапе линковки) может быть объединен с другими объектными файлами (при этом, в соответствии с таблицами символов, будут вычислены и заполнены адреса существующих между файлами перекрестных ссылок). Опция gcc -c, останавливает процесс по завершении этапа ассемблирования:

$ gcc -c hello.c
$ ls
hello.c hello.o
$ file hello.o
hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

Для объектных файлов принято стандартное расширение .o.

Если полученный объектный файл hello.o передать линковщику, последний вычислит адреса ссылок, добавит код запуска и завершения программы, код вызова библиотечных функций и в результате мы будем обладать готовым исполняемым файлом программы.

$ gcc -o hello hello.o
$ ls
hello hello.c hello.o
$ ./hello
Hello World

То, что мы сейчас проделали (вернее gcc проделал за нас) и есть содержание последнего этапа — линковки (связывания, компоновки).

Ну вот пожалуй о компиляции и все. Теперь коснемся некоторых, на мой взгляд важных, опций gcc.

Опция -Iпуть/к/каталогу/с/заголовочными/файлами — добавляет указанный каталог к списку путей поиска заголовочных файлов. Каталог, добавленный опцией -I просматривается первым, затем поиск продолжается в стандартных системных каталогах. Если опций -I несколько, заданные ими каталоги просматриваются слева на право, по мере появления опций.

Опция -Wall — выводит предупреждения, вызванные потенциальными ошибками в коде, не препятствующими компиляции программы, но способными привести, по мнению компилятора, к тем или иным проблемам при её исполнении. Важная и полезная опция, разработчики gcc рекомендуют пользоваться ей всегда. Например масса предупреждений будет выдана при попытке компиляции вот такого файла:

 1 /* remark.c */
 2 
 3 static int k = 0;
 4 static int l(int a);
 5 
 6 main()
 7 {
 8 
 9         int a;
10 
11         int b, c;
12 
13         b + 1;
14 
15         b = c;
16 
17         int *p;
18 
19         b = *p;
20 
21 }

$ gcc -o remark remark.c
$ gcc -Wall -o remark remark.c
remark.c:7: warning: return type defaults to ‘int’
remark.c: In function ‘main’:
remark.c:13: warning: statement with no effect
remark.c:9: warning: unused variable ‘a’
remark.c:21: warning: control reaches end of non-void function
remark.c: At top level:
remark.c:3: warning: ‘k’ defined but not used
remark.c:4: warning: ‘l’ declared ‘static’ but never defined
remark.c: In function ‘main’:
remark.c:15: warning: ‘c’ is used uninitialized in this function
remark.c:19: warning: ‘p’ is used uninitialized in this function

Опция -Werror — превращает все предупреждения в ошибки. В случае появления предупреждения прерывает процесс компиляции. Используется совместно с опцией -Wall.

$ gcc -Werror -o remark remark.c
$ gcc -Werror -Wall -o remark remark.c
cc1: warnings being treated as errors
remark.c:7: error: return type defaults to ‘int’
remark.c: In function ‘main’:
remark.c:13: error: statement with no effect
remark.c:9: error: unused variable ‘a’

Опция -g — помещает в объектный или исполняемый файл информацию необходимую для работы отладчика gdb. При сборке какого-либо проекта с целью последующей отладки, опцию -g необходимо включать как на этапе компиляции так и на этапе компоновки.

Опции -O1, -O2, -O3 — задают уровень оптимизации кода генерируемого компилятором. С увеличением номера, степень оптимизации возрастает. Действие опций можно увидеть вот на таком примере.

Исходный файл:

/* circle.c */

main(void)
{

        int i;

        for(i = 0; i < 10; ++i)
                ;

        return i;

}

Компиляция с уровнем оптимизации по умолчанию:

$ gcc -S circle.c
$ less circle.s
        .file   "circle.c"
        .text
.globl main
        .type   main, @function
main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $16, %esp
        movl    $0, -4(%ebp)
        jmp     .L2
.L3:
        addl    $1, -4(%ebp)
.L2:
        cmpl    $9, -4(%ebp)
        jle     .L3
        movl    -4(%ebp), %eax
        leave
        ret
        .size   main, .-main
        .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
        .section        .note.GNU-stack,"",@progbits

Компиляция с максимальным уровнем оптимизации:

$ gcc -S -O3 circle.c
$ less circle.s
        .file   "circle.c"
        .text
        .p2align 4,,15
.globl main
        .type   main, @function
main:
        pushl   %ebp
        movl    $10, %eax
        movl    %esp, %ebp
        popl    %ebp
        ret
        .size   main, .-main
        .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
        .section        .note.GNU-stack,"",@progbits

Во втором случае в полученном коде даже нет намёка на какой-либо цикл. Действительно, значение i, можно вычислить ещё на этапе компиляции, что и было сделано.

Увы, для реальных проектов разница в производительности при различных уровнях оптимизации практически не заметна…

Опция -O0 — отменяет какую-либо оптимизацию кода. Опция необходима на этапе отладки приложения. Как было показано выше, оптимизация может привести к изменению структуры программы до неузнаваемости, связь между исполняемым и исходным кодом не будет явной, соответственно, пошаговая отладка программы будет не возможна. При включении опции -g, рекомендуется включать и -O0.

Опция -Os — задает оптимизацию не по эффективности кода, а по размеру получаемого файла. Производительность программы при этом должна быть сопоставима с производительностью кода полученного при компиляции с уровнем оптимизации заданным по умолчанию.

Опция -march=architecture — задает целевую архитектуру процессора. Список поддерживаемых архитектур обширен, например, для процессоров семейства Intel/AMD можно задать i386, pentium, prescott, opteron-sse3 и т.д. Пользователи бинарных дистрибутивов должны иметь в виду, что для корректной работы программ с указанной опцией желательно, что бы и все подключаемые библиотеки были откомпилированы с той же опцией.

Об опциях передаваемых линковщику будет сказано ниже.

Собственно о компиляции все. Далее поговорим о раздельной компиляции и создании библиотек.

Небольшое дополнение:

Выше было сказано, что gcc определяет тип (язык программирования) переданных файлов по их расширению и, в соответствии с угаданным типом (языком), производит действия над ними. Пользователь обязан следить за расширениями создаваемых файлов, выбирая их так, как того требуют соглашения gcc. В действительности gcc можно подсовывать файлы с произвольными именами. Опция gcc -x позволяет явно указать язык программирования компилируемых файлов. Действие опции распространяется на все последующие перечисленные в команде файлы (вплоть до появления следующей опции -x). Возможные аргументы опции:

c                 c-header                 c-cpp-output

c++               c++-header               c++-cpp-output

objective-c       objective-c-header       objective-c-cpp-output

objective-c++     objective-c++-header     objective-c++-cpp-output

assembler         assembler-with-cpp

ada

f77               f77-cpp-input

f95               f95-cpp-input

java

Назначение аргументов должно быть понятно из их написания (здесь cpp не имеет ни какого отношения к C++, это файл исходного кода предварительно обработанный препроцессором). Проверим:

$ mv hello.c hello.txt
$ gcc -Wall -x c -o hello hello.txt
$ ./hello
Hello World

Раздельная компиляция

Сильной стороной языков C/C++ является возможность разделять исходный код программы по нескольким файлам. Даже можно сказать больше — возможность раздельной компиляции это основа языка, без неё эффективное использование C не мыслимо. Именно мультифайловое программирование позволяет реализовать на C крупные проекты, например такие как Linux (здесь под словом Linux подразумевается как ядро, так и система в целом). Что даёт раздельная компиляция программисту?

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

2. Позволяет сократить время повторной компиляции проекта. Если изменения внесены в один файл нет смысла перекомпилировать весь проект, достаточно заново откомпилировать только этот изменённый файл.

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

4. Без раздельной компиляции не существовало бы библиотек. Посредством библиотек реализовано повторное использование и распространение кода на C/C++, причем кода бинарного, что позволяет с одной стороны предоставить разработчикам простой механизм включения его в свои программы, с другой стороны скрыть от них конкретные детали реализации. Работая над проектом, всегда стоит задумываться над тем, а не понадобиться что-либо из уже сделанного когда-нибудь в будущем? Может стоит заранее выделить и оформить часть кода как библиотеку? По моему, такой подход, существенно упрощает жизнь и экономит массу времени.

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

Вот практический пример (правда весьма и весьма условный).

Набор файлов исходного кода:

/* main.c */

#include <stdio.h>

#include "first.h"
#include "second.h"

int main(void)
{

        first();
        second();

        printf("Main function...n");

        return 0;

}

/* first.h */

void first(void);

/* first.c */

#include <stdio.h>

#include "first.h"

void first(void)
{

        printf("First function...n");

}

/* second.h */

void second(void);

/* second.c */

#include <stdio.h>

#include "second.h"

void second(void)
{

        printf("Second function...n");

}

В общем имеем вот что:

$ ls
first.c first.h main.c second.c second.h
Все это хозяйство можно скомпилировать в одну команду:

$ gcc -Wall -o main main.c first.c second.c
$ ./main
First function…
Second function…
Main function…

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

$ gcc -Wall -c main.c
$ gcc -Wall -c first.c
$ gcc -Wall -c second.c
$ ls
first.c first.h first.o main.c main.o second.c second.h second.o
$ gcc -o main main.o first.o second.o
$ ./main
First function…
Second function…
Main function…

Что мы сделали? Из каждого исходного файла (компилируя с опцией -c) получили объектный файл. Затем объектные файлы слинковали в итоговый исполняемый. Разумеется команд gcc стало больше, но в ручную ни кто проекты не собирает, для этого есть утилиты сборщики (самая популярная make). При использовании утилит сборщиков и проявятся все из перечисленных выше преимуществ раздельной компиляции.

Возникает вопрос: как линковщик ухитряется собирать вместе объектные файлы, правильно вычисляя адресацию вызовов? Откуда он вообще узнаёт, что в файле second.o содержится код функции second(), а в коде файла main.o присутствует её вызов? Оказывается всё просто — в объектном файле присутствует так называемая таблица символов, включающая имена некоторых позиций кода (функций и внешних переменных). Линковщик просматривает таблицу символов каждого объектного файла, ищет общие (с совпадающими именами) позиции, на основании чего делает выводы о фактическом местоположении кода используемых функций (или блоков данных) и, соответственно, производит перерасчёт адресов вызовов в исполняемом файле.

Просмотреть таблицу символов можно с помощью утилиты nm.

$ nm main.o
         U first
00000000 T main
         U puts
         U second
$ nm first.o
00000000 T first
         U puts
$ nm second.o
         U puts
00000000 T second

Появление вызова puts объясняется использованием функции стандартной библиотеки printf(), превратившейся в puts() на этапе компиляции.

Таблица символов прописывается не только в объектный, но и в исполняемый файл:

$ nm main
08049f20 d _DYNAMIC
08049ff4 d _GLOBAL_OFFSET_TABLE_
080484fc R _IO_stdin_used
         w _Jv_RegisterClasses
08049f10 d __CTOR_END__
08049f0c d __CTOR_LIST__
08049f18 D __DTOR_END__
08049f14 d __DTOR_LIST__
08048538 r __FRAME_END__
08049f1c d __JCR_END__
08049f1c d __JCR_LIST__
0804a014 A __bss_start
0804a00c D __data_start
080484b0 t __do_global_ctors_aux
08048360 t __do_global_dtors_aux
0804a010 D __dso_handle
         w __gmon_start__
080484aa T __i686.get_pc_thunk.bx
08049f0c d __init_array_end
08049f0c d __init_array_start
08048440 T __libc_csu_fini
08048450 T __libc_csu_init
         U __libc_start_main@@GLIBC_2.0
0804a014 A _edata
0804a01c A _end
080484dc T _fini
080484f8 R _fp_hw
080482b8 T _init
08048330 T _start
0804a014 b completed.7021
0804a00c W data_start
0804a018 b dtor_idx.7023
0804840c T first
080483c0 t frame_dummy
080483e4 T main
         U puts@@GLIBC_2.0
08048420 T second

Включение таблицы символов в исполняемый файл в частности необходимо для упрощения отладки. В принципе для выполнения приложения она не очень то и нужна. Для исполняемых файлов реальных программ, с множеством определений функций и внешних переменных, задействующих кучу разных библиотек, таблица символов становиться весьма обширной. Для сокращения размеров выходного файла её можно удалить, воспользовавшись опцией gcc -s.

$ gcc -s -o main main.o first.o second.o
$ ./main
First function…
Second function…
Main function…
$ nm main
nm: main: no symbols

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

http://pyviy.blogspot.ru/2010/12/gcc.html

error with code

cant figure out how to fix this error. here is the error code i get:
line col
11 9 [Error] statement has no effect [-Werror=unused-value]
11 9 [Error] statement is a reference, not call, to function ‘ifPrime’ [-Werror=address]
12 6 [Error] unused variable ‘value’ [-Werror=unused-variable]

help is greatly appreciated.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
 
#include <iostream>
 #include <fstream>
 using namespace std;

void ifPrime(int, int, int);

int main()
 {
 ifstream inFile;
 ifstream savedata;
 ifPrime;
 int value;
	int value1; 
	int value2; 
	int value3; 
	int value4; 
	int value5; 
	int value6;
	int value7; 
	int value8;
	int value9;
	int value10; 
	int value11;
	int value12; 
	int value13; 
	int value14; 
	int value15; 
	int value16; 
	int value17; 
	int value18; 
	int value19; 
	int value20;
    int value21; 
	int value22; 
	int value23;
	int value24; 
	int value25; 
	int value26; 
	int value27; 
	int value28;
	int value29; 
	int value30; 
	int value31; 
	int value32; 
	int value33; 
	int value34; 
	int value35; 
	int value36; 
	int value37; 
	int value38; 
	int value39;
	int value40;
    int value41;
	int value42; 
	int value43; 
	int value44; 
	int value45; 
	int value46; 
	int value47;
	int value48; 
	int value49; 
	int value50;

 inFile.open("numbersinput.txt");
 cout << "reading data from the file" << endl;

 			inFile >> value1; 
            inFile >> value2; 
            inFile >> value3; 
			inFile >> value4; 
            inFile >> value5; 
            inFile >> value6; 
            inFile >> value7; 
            inFile >> value8;
            inFile >> value9;
            inFile >> value10;
            inFile >> value11; 
            inFile >> value12; 
            inFile >> value13; 
            inFile >> value14; 
            inFile >> value15; 
            inFile >> value16; 
            inFile >> value17; 
            inFile >> value18;
            inFile >> value19;
            inFile >> value20;
            inFile >> value21; 
            inFile >> value22; 
            inFile >> value23; 
            inFile >> value24; 
            inFile >> value25; 
            inFile >> value26; 
            inFile >> value27; 
            inFile >> value28;
            inFile >> value29;
            inFile >> value30;
            inFile >> value31; 
            inFile >> value32; 
            inFile >> value33; 
            inFile >> value34; 
			inFile >> value35;
			inFile >> value36;  
            inFile >> value37; 
            inFile >> value38;
            inFile >> value39;
            inFile >> value40;
            inFile >> value41;
            inFile >> value42;
            inFile >> value43;
            inFile >> value44;
            inFile >> value45;
            inFile >> value46;
            inFile >> value47;
            inFile >> value48;
            inFile >> value49;
            inFile >> value50;
            inFile.close();
            
            cout << "now saving numbers";
            
          savedata.open("inputnumbers.txt");
          	savedata >> value1; 
            savedata >> value2; 
            savedata >> value3; 
			savedata >> value4; 
           	savedata >> value5; 
            savedata >> value6; 
            savedata >> value7; 
            savedata >> value8;
            savedata >> value9;
            savedata >> value10;
            savedata >> value11; 
            savedata >> value12; 
            savedata >> value13; 
            savedata >> value14; 
            savedata >> value15; 
            savedata >> value16; 
            savedata >> value17; 
            savedata >> value18;
			savedata >> value19;
            savedata >> value20;
            savedata >> value21; 
            savedata >> value22; 
            savedata >> value23; 
            savedata >> value24; 
            savedata >> value25; 
            savedata >> value26; 
            savedata >> value27; 
            savedata >> value28;
            savedata >> value29;
            savedata >> value30;
            savedata >> value31; 
            savedata >> value32; 
            savedata >> value33; 
            savedata >> value34; 
			savedata >> value35;
			savedata >> value36;  
            savedata >> value37; 
            savedata >> value38;
            savedata >> value39;
            savedata >> value40;
            savedata >> value41;
            savedata >> value42;
            savedata >> value43;
			savedata >> value44;
            savedata >> value45;
            savedata >> value46;
            savedata >> value47;
            savedata >> value48;
            savedata >> value49;
            savedata >> value50;
     		savedata.close();
    ifPrime(value1, value2, value3);
        return 0;
        
}

 void IfPrime(int value1, int value2, int value3)
{
	if (value1 /=1, value1/=value1)
	{
		cout << "this number is prime";
	}
	else 
	{
		cout << "this number isnt prime";
	}
}

here is the numbers for the numbersinput file:

2529
2286
1253
1029
692
117
1984
1524
804
154
1068
626
2037
573
177
242
1676
914
1878
278
1851
2875
28
714
1492
244
297
185
50
425
395
317
345
67
221
33
19
141
40
126
76
35
11
77
36
140
105
20
9
5

Hi Ghostman513,

This program seems like a good chance to use a loop. A for loop has the following syntax:

1
2
3
for( initialValue ; conditional ; update ) {
       // Do stuff as long as the conditional is true here
}

Your conditionals for the ifPrime() function are also off.

Here is a link that will explain these things better than I can:
http://www.cplusplus.com/doc/tutorial/control/

Below is a restructured version of your program, although the ifPrime() function is still not correct:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <fstream>
#include <cassert> // assert()

#define NUM_VALUES 50 // Easier to maintain/edit

using namespace std;

void ifPrime(int, int, int);

int main()
{
	ifstream inFile;
	//ifstream savedata;
	ofstream savedata; // This should be an output file stream, not an input file stream
	//ifPrime; What is this line supposed to do?
	int values[NUM_VALUES]; // Declares NUM_VALUES number of integer variables

	inFile.open("numbersinput.txt");
	assert(inFile); // Verifies file was found

	cout << "Reading data from the file..." << endl;

	for(unsigned int i = 0; i < NUM_VALUES; i++) {
		inFile >> values[i];
	}
	
	inFile.close();

	cout << "Now saving numbers...";

	savedata.open("inputnumbers.txt");
	assert(savedata); // Verifies file was opened

	for(unsigned int i = 0; i < NUM_VALUES; i++) {
		savedata << values[i];
	}

	savedata.close();

	ifPrime(values[0], values[1], values[2]);

	return 0;
}

//void IfPrime(int value1, int value2, int value3)
void ifPrime(int value1, int value2, int value3)
{
	//if( value1 /= 1, value1 /= value1 ) This is not a conditional (the way you intend at least)
	if( (value1 /= 1) == ?? || (value1 /= value1) == ?? ) // Every real number is divisible by one and itself
	{
		cout << "this number is prime";
	} else
	{
		cout << "this number isnt prime";
	}
}

You’re on the right track for the ifPrime function. I would use the modulus operator (%) which will return the remainder of division. EX: 15 % 2 = 1, since 15 / 2 has one as a remainder. Using that and a loop, iterate through values less than the value1 and break if value1 % loopCount equals 0. Additionally, why are there 3 values being passed to ifPrime? It only uses one of them.

Last edited on

this is for a project where they want us to test 50 numbers from an input file test them to see if they are prime and then if they are prime to put them in an output file.

In this situation, there is no need to store all the values from the file, not in an array, nor in many separate variables.

Just read a single value from the file, test whether or not it is prime, write it to the output file only if it is prime. Repeat.

Function ifprime should have a return type of bool and take a single parameter, the number being tested. Return true in the case of a prime number, otherwise return false.

bool ifPrime(int);

The errors you posted are on lines 12 and 13 of the code you posted:

11 9 [Error] statement has no effect [-Werror=unused-value]
The statement ifPrime; does not call ifPrime, it just returns the function’s address, which is then thrown away. So the

on the program.

11 9 [Error] statement is a reference, not call, to function ‘ifPrime’ [-Werror=address]

Like I said, that statement doesn’t call function ifPrime.

12 6 [Error] unused variable ‘value’ [-Werror=unused-variable]
At line 13 you declare variable «value», but you never use it in the program.

One other bug: function names in C++ are case sensitive, so the function ifPrime() that you declare at line 6 is NOT the same as the function IfPrime that you call define at line 179

> this is for a project where they want us to test 50 numbers from an input file
> test them to see if they are prime and then if they are prime to put them in an output file.

Chervil +1
>> there is no need to store all the values from the file, not in an array, nor in many separate variables.
>> Just read a single value from the file, test whether or not it is prime,
>> write it to the output file only if it is prime. Repeat.

Something along these lines:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <fstream>

// return true if n is a prime number; false otherwise
bool is_prime( int n )
{
    if( n < 2 ) return false ; // less than two: not prime
    if( n == 2 ) return true ; // two: prime
    if( n%2 == 0 ) return false ; // even number greater than two: not prime

    // TO DO rest of the code for the function
    // check if n is divisible by any number 3, 5, 7, 9 ... less than n 
    //      (less than or equal to square root of n, if we want to get fancy)
    // if it is divisible, it is not a prime; return false 

    return true ; // if n comes through the division tests
}

int main()
{
    const char* input_file_name = "numbersinput.txt" ;
    const char* output_file_name = "output.txt" ;

    std::ifstream input_file(input_file_name) ; // ifstream: open for input
    std::ofstream output_file(output_file_name) ; // ofstream: open for output

    int number ; // number to be read in from the input file
    while( input_file >> number ) // for each number read from the input file
    {
        if( is_prime(number) ) // if it is a prime number
        {
            output_file << number << 'n' ; // write it to the output file
        }
    }
}

Topic archived. No new replies allowed.

Понравилась статья? Поделить с друзьями:
  • Error statement has no effect
  • Error stray 363 in program
  • Error statement cannot resolve address of overloaded function
  • Error stray 361 in program
  • Error state фильтр калмана