Search code, repositories, users, issues, pull requests…
Provide feedback
Saved searches
Use saved searches to filter your results more quickly
Sign up
Я новичок в C ++, нет знаний по C ++. Я пишу код для студента и модуля. Требуется, чтобы модуль и ученик отображали итоговую оценку, а также дублирование. Когда я пишу случай 5 и случай 6, после компиляции он показывает ошибку ниже.
ошибка C2360: инициализация кода пропускается по метке case
см объявление «код»
ошибка C2361: инициализация «кода» пропускается по метке «по умолчанию»
см объявление «код»
ошибка C2039: ‘getId’: не является членом ‘std :: vector<_Ty>»
с [_Ty = Student]
ошибка C2039: «getModule»: не является членом «std :: vector»<_Ty>»
с [_Ty = Student]
main.cpp
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>
#include <cmath>
#include <vector>
#include "Student.h"#include "Module.h"using namespace std;
void printMenu();
vector<Student> readFile();
void liststudentRecord(vector<Student>);
string trim(string);
bool isValidClasscode(string s);
bool isvalidStudentid(string s);
bool test1Ascending(Student s1, Student s2);
bool test1Desscending(Student s1, Student s2);
bool test1finalScoreAscending(Student s1, Student s2);
vector<Module> readFile2();
void listmoduleRecord(vector<Module>);
bool moduleName (Module m1, Module m2);
vector<Student> getStudentByModule(vector<Student>,string);
bool isDuplicateStudentRecord(vector<Student>, Student);//gloval variable
vector<Student> duplicates;
int main() {
int choice;
vector<Student> students;//list of student
vector<Module> modules;
vector<Student> list;do {
printMenu();
cin >> choice;
switch(choice) {
case 1:
cout << "Read Student file ... " << endl;
students =readFile();
cout<<"Number of records read: " <<students.size() <<endl;
break;
case 2:
liststudentRecord(students);
break;
case 3:
cout << "Read Module file ... " << endl;
modules =readFile2();
cout<<"Number of records read: " <<modules.size() <<endl;
break;
case 4:
listmoduleRecord(modules);
break;
case 5:
liststudentRecord(duplicates);
break;
case 6:
cout << "Enter Module Code: ";
string code;
cin >> code;
list = getStudentByModule(students, code);
for (int i=0; i < list.size(); i++ ){
Student s = list.at(i);
cout << s.toString() << endl;
}
cout<<"List Student by Module Code"<<endl;
break;
case 7:
//http://www.cplusplus.com/reference/algorithm/sort/
//sort(students.begin(), students.end(), test1finalScoreAscending);
sort(students.begin(), students.end(),test1finalScoreAscending); //finalScoreAcending
break;
case 8:
break;
case 9: cout << "Exiting program... " << endl; break;
default:
cout << "Invalid option specified. Please try again" << endl;
}
} while(choice != 9);
return 0;
}
void printMenu() {
cout << "Menu" << endl;
cout << "----" << endl;
cout << "[1] Read student file" << endl;
cout << "[2] List student records" << endl;
cout << "[3] Read module file" << endl;
cout << "[4] List module records" << endl;
cout << "[5] List Duplicate Record" << endl;
cout << "[6] Display Student by Module" << endl;
cout << "[7] Sort by Final Score" <<endl;
cout << "[8] Write to file" << endl;
cout << "[9] Exit" << endl;
cout << "Choice: ";
}
vector<Student>readFile(){
vector<Student>students;
string filename;
ifstream inputFile;
cout << "Enter filename: ";
cin >> filename;
inputFile.open(filename, ios::in);//open file, read only
if(inputFile.is_open()){
while (inputFile.good()){
string line;
getline(inputFile, line);
Student s; //create a new student
//extract id
int i = line.find(",");
string id = trim(line.substr(0, i));// extract id
s.setId(id); // set student id
line = line.substr(i+1);// remove id form line
/*if(isvalidStudentid(id)){
string s = id.substr(0,1);
const char* s = id.substr(1,7);
}*/
//extract name
i = line.find(",");
string name = trim(line.substr(0, i)); // extract name
s.setName(name); //set student name
line = line.substr(i+1); //remove name from line
//extract classcode
i = line.find(",");
string classcode = trim(line.substr(0, i));
s.setClasscode(classcode);
line = line.substr(i+1);
if(isValidClasscode(classcode)){
string module = classcode.substr(0,6);
s.setModule(module);
string status = classcode.substr(7,9);
char *ft ="FT";
if(status.compare(ft)==0){
s.setFulltime(true);
}else{
s.setFulltime(false);
}
string classnumber = classcode.substr(9,11);
s.setClassnumber(classnumber);
}//to use a for-loop for attendance
for (int j =0; j < 10 ; j++){
i = line.find(",");
string attendance = trim(line.substr(0, i));
s.setAttendance(j, attendance);
line = line.substr(i+1);
}
//to extreact test1
i = line.find(",");
int test1 = stoi(line.substr(0, i));
s.setTest1(test1);
line = line.substr(i+1);
//to extreact test2
i = line.find(",");
int test2 = stoi(line.substr(0, i));
s.setTest2(test2);
line = line.substr(i+1);//to extreact tutorial
i = line.find(",");
int tutorial = stoi(line.substr(0, i));
s.setTutorial(tutorial);
line = line.substr(i+1);
//to extreact exam
i = line.find(",");
int exam = stoi(line.substr(0, i));
s.setExam(exam);
line = line.substr(i+1);//need to do validationfirst
//to only add the valid student
if(isDuplicateStudentRecord(students, s) == false){
students.push_back(s); //add student to list
} else {
duplicates.push_back(s);
}
//cout<< line << endl;
}
inputFile.close();
}else{
cout << "Invalid file" << endl;
}
return students;
}
void liststudentRecord(vector<Student> list){
int numberStudents = list.size();
if (numberStudents > 0){
for (int i = 0; i < numberStudents; i++){
Student s = list.at(i);
cout << s.toString() << endl;
}
}else{
cout << "Empty list" <<endl;
}
}
bool test1Ascending(Student s1, Student s2){
return s1.getTest1() < s2.getTest1();
}
bool test1Descending(Student s1, Student s2){
return s1.getTest1() < s2.getTest1();
}
bool finalScoreAscending(Student s1, Student s2){
return s1.getFinalScore() < s2.getFinalScore();
}
bool isvalidStudentid(string s){
int i;
if(s.length() !=8){
return false;} //first check th length is 8
if (s.at(i) != 'S') {
return false;} //start with s
for (i =1 ; i<8; i++){ //7 digit
if(isdigit(s.at(i))==0){
return false;
}
}
return false;
}
bool isValidClasscode(string s){
int i;
if(s.length() !=11){
return false;} //first check th length is 8for (i =0 ; i<3; i++){ // first 3 char are letters
if(isalpha(s.at(i))==0){
return false;}
}
for (i =3 ; i<6; i++){ //next 3 char are number
if(isdigit(s.at(i)) == 0){
return false;}
}
if (s.at(6) != '-') {
return false;} //has a hyphen
if (s.at(7) != 'F' && s.at(7) != 'P') {
return false;}
if (s.at(8) != 'T' ) {
return false;} // T
if (isdigit(s.at(9)) == 0 || isdigit(s.at(10)) == 0){
return false;}return false;
}
vector<Module> readFile2(){
vector<Module>modules;
string filename;
ifstream inputFile;
cout << "Enter filename: ";
cin >> filename;
inputFile.open(filename, ios::in);//open file, read only
if(inputFile.is_open()){
while (inputFile.good()){
string line;
getline(inputFile, line);
Module m; //create a new student
//extract name
int i = line.find(",");
string modulecode = trim(line.substr(0, i));// extract id
m.setModulecode(modulecode); // set student id
//cout << id<< endl;
line = line.substr(i+1);// remove id form line
//cout << line << endl;
//extract id
i = line.find(",");
string modulename = trim(line.substr(0, i)); // extract name
m.setModulename(modulename); //set student name
line = line.substr(i+1); //remove name from line//to extreact test1
i = line.find(",");
int test1 = stoi(line.substr(0, i));
m.setTest1(test1);
line = line.substr(i+1);
//to extreact test2
i = line.find(",");
int test2 = stoi(line.substr(0, i));
m.setTest2(test2);
line = line.substr(i+1);//to extreact tutorial
i = line.find(",");
int tutorial = stoi(line.substr(0, i));
m.setTutorial(tutorial);
line = line.substr(i+1);
//to extreact exam
i = line.find(",");
int exam = stoi(line.substr(0, i));
m.setExam(exam);
line = line.substr(i+1);
modules.push_back(m); //add student to list
//cout<< line << endl;
}
inputFile.close();
}else{
cout << "Invalid file" << endl;
}
return modules;
}
void listmoduleRecord(vector<Module> list){
int numberModules = list.size();
if (numberModules > 0){
for (int i = 0; i < list.size(); i++){
Module m = list.at(i);
cout << m.toString() << endl;
}
}else{
cout << "Empty list" <<endl;
}
}
vector<Student> getStudentByModule(vector<Student> students,string code){
vector<Student> list;
for (int i=0; i< students.size(); i++){
Student s = students.at(i);
if (code.compare(current_module) == 0){
list.push_back(s);
}
}
return list;
}bool isDuplicateStudentRecord(vector<Student> student, Student s){
string id = student.getId();
string name = student.getName();
string module = student.getModule();
for(int i=0; i< student.size(); i++){
Student s = student.at(i);
string current_id = s.getId();
string current_name = s.getName();
string current_module = s.getModule();
if(id.compare)(current_id) == 0 &&
name.compare(current_name) == 0 &&
(module.compare(current_module) == 0);{
return true;
}
}
return false;
}//http://stackoverflow.com/a/6500499/3839235
string trim(string s){
s.erase(0, s.find_first_not_of(' ')); //prefixing spaces
s.erase(s.find_last_not_of(' ')+1); //surfixing spaces
return s;
}
Module.cpp
#include "Module.h"#include <sstream>
using namespace std;
Module::Module(void){
}string Module:: getModulecode(){
return modulecode;
}
void Module::setModulecode(string modulecode){
this->modulecode = modulecode;
}
string Module:: getModulename(){
return modulename;
}
void Module:: setModulename(string modulename){
this->modulename = modulename;
}
int Module:: getTest1(){
return test1;
}
void Module:: setTest1(int value1){
test1 = value1;
}
int Module:: getTest2(){
return test2;
}
void Module:: setTest2(int value2){
test2 = value2;
}
int Module:: getTutorial(){
return tutorial;
}
void Module:: setTutorial(int value3){
tutorial = value3;
}
int Module:: getExam(){
return exam;
}
void Module:: setExam(int value4){
exam = value4;
}string Module::toString(){
stringstream ss;
ss<<"Module Code: " << modulecode<< "-"<< modulename <<endl;
ss << "Test 1: " << getTest1Percentage() << "%" << endl;
ss << "Test 2: " << getTest2Percentage() << "%" << endl;
ss << "Tutorial: " << getTutorialPercentage() << "%" << endl;
ss << "Exam: " << getExamPercentage() << "%" << endl;
//ss<< "Score percentage: " << getScorePercentage() << "%"<< endl;
ss<< "Final score: " << getFinalScore() << "%" <<endl;
return ss.str();
}
int Module::getTest1Percentage(){
int result;
result = (getTest1() * 100) / 100;
return result;
}
int Module::getTest2Percentage(){
int result;
result = (getTest2() * 100) / 100;
return result;
}
int Module::getTutorialPercentage(){
int result;
result = (getTutorial() * 100) / 100;
return result;
}
int Module::getExamPercentage(){
int result;
result = (getExam() * 100) / 100;
return result;
}
int Module::getFinalScore(){
int final = getTest1Percentage()+getTest2Percentage()+getTutorialPercentage()+getExamPercentage();
return final;
}/*int Module::getFinalScore(){
int final = test1+test2+tutorial+exam;
return final;
}*/
Student.cpp
#include "Student.h"#include <sstream>
using namespace std;
Student::Student(void){
}string Student:: getId(){
return id;
}
void Student:: setId(string newid){
id = newid;
}
string Student:: getName(){
return name;
}
void Student:: setName(string name){
this->name = name;
}
string Student:: getClasscode(){
return classcode;
}
void Student::setClasscode(string classcode){
this->classcode = classcode;
}
string Student:: getAttendance(int i){
return attendance[i];
}
void Student:: setAttendance(int i, string value){
attendance[i] = value;
}
int Student:: getTest1(){
return test1;
}
void Student:: setTest1(int value1){
test1 = value1;
}
int Student:: getTest2(){
return test2;
}
void Student:: setTest2(int value2){
test2 = value2;
}
int Student:: getTutorial(){
return tutorial;
}
void Student:: setTutorial(int value3){
tutorial = value3;
}
int Student:: getExam(){
return exam;
}
void Student:: setExam(int value4){
exam = value4;
}string Student::toString(){
stringstream ss;
ss << name << "(" <<id << ")" << endl;
ss << classcode << endl;
for(int i=0; i<10; i++){
ss << getAttendance(i) << " ";
}
ss << endl;
ss << "Test 1: " << test1 << endl;
ss << "Test 2: " << test2 << endl;
ss << "Tutorial: " << tutorial << endl;
ss << "Exam: " << exam << endl;
ss<< "Attendance percentage: " << getAttendancePercentage() << "%"<< endl;
ss<< "Final score: " << getFinalScore() <<endl;
return ss.str();
}double Student::getAttendancePercentage(){
int n =0 ; // n will be the total number of "yes"for (int i=1; i<10; i++){
string s = getAttendance(i);
char*yes = "yes";
if(s.compare(yes)== 0){
n++;
}
}
double percentage = n/10.0 * 100; //avoud interger division
return percentage;
}int Student::getFinalScore(){
int final = test1+test2+tutorial+exam;
return final;
}
/*string Student::getModule() { return module; }
void Student::setModule(string m) { module = m;}
bool Student::getFulltime() { return fulltime; }
void Student::setFulltime(bool v) { fulltime = v;}
string Student::getClassnumber() { return classnumber; }
void Student::setClassnumber(string v) { classnumber = v;} */string Student:: getModule(){
return module;
}
void Student:: setModule(string m){
module =m;
}
bool Student:: getFulltime(){
return fulltime;
}
void Student:: setFulltime(bool v){
fulltime = v;
}
string Student:: getClassnumber(){
return classnumber;
}
void Student:: setClassnumber(string c){
classnumber = c;
}
module.h
#ifndef MODULE_H
#define MODULE_H
#include <string>
using namespace std;
class Module {
public:
Module();
string getModulecode();
void setModulecode(string);
string getModulename();
void setModulename(string);
int getTest1();
void setTest1(int);
int getTest2();
void setTest2(int);
int getTutorial();
void setTutorial(int);
int getExam();
void setExam(int);
string toString(); //to displayed info
int getTest1Percentage();
int getTest2Percentage();
int getTutorialPercentage();
int getExamPercentage();
int getFinalScore();
private:
string modulecode;
string modulename;
int test1;
int test2;
int tutorial;
int exam;
};#endif //MODULE_H
Student.h
#ifndef STUDENT_H
#define STUDENT_H
#include <string>
using namespace std;
class Student {
//methods
public:
Student();
string getId();
string getName();
string getClasscode();
string getAttendance(int);
int getTest1();
int getTest2();
int getTutorial();
int getExam();
void setId(string);
void setName(string);
void setClasscode(string);
void setAttendance(int, string);
void setTest1(int);
void setTest2(int);
void setTutorial(int);
void setExam(int);
string toString(); //to displayed info
double getAttendancePercentage();
int getFinalScore();
string getModule();
void setModule(string);
bool getFulltime();
void setFulltime(bool);
string getClassnumber();
void setClassnumber(string);
//to create the get and set methods for all the attributes//attribute
private:
string id;
string name;
string classcode;
string module;
bool fulltime;
string classnumber;
string attendance[10];
int test1;
int test2;
int tutorial;
int exam;
};
#endif //STUDENT_Hs
1
Решение
Из первой ошибки, о которой вы упомянули, кажется, что ваш компилятор жалуется на создание вашей строковой переменной ‘code’ внутри случая 6. Попробуйте переместить создание переменной туда, где вы сделали другие выше. Это должно исправить первую ошибку, которую вы получили.
Что касается второй и третьей ошибки, она говорит вам, что функции ‘getId’ и ‘getModule’ являются функциями из вашего класса ‘module’, что означает, что вы можете вызывать их только в экземплярах класса ‘module’. Тем не менее, вы пытаетесь вызвать их на вектор студенческих объектов.
2
Другие решения
Это плохая идея объявить переменную внутри switch заявление:
switch(i) {
case 1:
int foo = 42;
doSomething(foo);
break;
case 2:
// aargh `foo` is in scope but uninitialised if we jump to here
...
}
Чтобы это исправить, либо принесите int foo вне switch или поместите его в локальную область switch заявление:
switch(i) {
case 1:
{
int foo = 42;
doSomething(foo);
} // foo is destroyed
break;
case 2:
// there is no foo, there is no problem
...
}
После внесения этих изменений я отправил ваш код в формат clang и онлайн-компилятор Clang, потому что в Clang есть прекрасные сообщения об ошибках. Вот что должен сказать Кланг:
prog.cc:69:27: warning: comparison of integers of different signs: 'int' and 'size_type' (aka 'unsigned long') [-Wsign-compare]
for (int i = 0; i < list.size(); i++) {
~ ^ ~~~~~~~~~~~
prog.cc:151:20: warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings]
char *ft = "FT";
^
prog.cc:243:12: warning: variable 'i' is uninitialized when used here [-Wuninitialized]
if (s.at(i) != 'S') {
^
prog.cc:237:8: note: initialize the variable 'i' to silence this warning
int i;
^
= 0
prog.cc:364:23: warning: comparison of integers of different signs: 'int' and 'size_type' (aka 'unsigned long') [-Wsign-compare]
for (int i = 0; i < list.size(); i++) {
~ ^ ~~~~~~~~~~~
prog.cc:377:22: error: use of undeclared identifier 'current_module'
if (code.compare(current_module) == 0) {
^
prog.cc:375:21: warning: comparison of integers of different signs: 'int' and 'size_type' (aka 'unsigned long') [-Wsign-compare]
for (int i = 0; i < students.size(); i++) {
~ ^ ~~~~~~~~~~~~~~~
prog.cc:385:23: error: no member named 'getId' in 'std::__1::vector<Student, std::__1::allocator<Student> >'
string id = student.getId();
~~~~~~~ ^
prog.cc:386:25: error: no member named 'getName' in 'std::__1::vector<Student, std::__1::allocator<Student> >'
string name = student.getName();
~~~~~~~ ^
prog.cc:387:27: error: no member named 'getModule' in 'std::__1::vector<Student, std::__1::allocator<Student> >'
string module = student.getModule();
~~~~~~~ ^
prog.cc:393:12: error: reference to non-static member function must be called
if (id.compare)
~~~^~~~~~~
( snipped: a lot of suggestions for what you might have meant instead )
prog.cc:394:20: error: invalid operands to binary expression ('string' (aka 'basic_string<char, char_traits<char>, allocator<char> >') and 'int')
(current_id) == 0 && name.compare(current_name) == 0 &&
~~~~~~~~~~~~ ^ ~
prog.cc:384:64: warning: unused parameter 's' [-Wunused-parameter]
bool isDuplicateStudentRecord(vector<Student> student, Student s) {
^
prog.cc:388:21: warning: comparison of integers of different signs: 'int' and 'size_type' (aka 'unsigned long') [-Wsign-compare]
for (int i = 0; i < student.size(); i++) {
~ ^ ~~~~~~~~~~~~~~
7 warnings and 6 errors generated.
Некоторые из них являются незначительными (но стоит исправить, например, for(size_t i = 0... вместо int), но те, которые отмечены как «ошибка», более критичны. Как правило, рекомендуется настроить компилятор так, чтобы он предупреждал обо всем, а затем убрал все предупреждения.
Вы можете увидеть код (с дополнительными скобками в switch и все в формате clang в стиле LLVM) в онлайн-компиляторе Clang здесь: http://melpon.org/wandbox/permlink/qLnE80Hs6FJWl9Fy
student.getID() ошибки возникают потому что в этой функции:
bool isDuplicateStudentRecord(vector<Student> student, Student s) {
string id = student.getId();
string name = student.getName();
string module = student.getModule();
...
ты пытаешься getID() на vector<Student> не на Student, Ты имел ввиду string id = s.getID();?
1
После изменений.
case 6:{
cout << "Enter Module Code: ";
string code;
cin >> code;
list = getStudentByModule(students, code);
for (int i=0; i < list.size(); i++ ){
Student s = list.at(i);
cout << s.toString() << endl;
}
cout<<"List Student by Module Code"<<endl;
break;
}
vector<Student> getStudentByModule(vector<Student> students,string code){
vector<Student> list;
for (int i=0; i< students.size(); i++){
Student s = students.at(i);
if (code.compare(current_module) == 0){
list.push_back(s);
}
}
return list;
}
дубликаты
bool isDuplicateStudentRecord(vector<Student> student, Student s){
string id = s.getId();
string name = s.getName();
string module = s.getModule();
for(int i=0; i< student.size(); i++){
Student s = student.at(i);
string current_id = s.getId();
string current_name = s.getName();
string current_module = s.getModule();
if(id.compare)(current_id) == 0 &&
name.compare(current_name) == 0 &&
(module.compare(current_module) == 0);{
return true;
}
ошибка показать ниже.
1> c: \ users \ cry83 \ documents \ visual studio 2010 \ projects \ partb \ partb \ partb.cpp (378): ошибка C2065: ‘current_module’: необъявленный идентификатор
1> c: \ users \ cry83 \ Documents \ visual studio 2010 \ projects \ partb \ partb \ partb.cpp (391): предупреждение C4018: ‘<‘: несоответствие со знаком / без знака
1> c: \ users \ cry83 \ documents \ visual studio 2010 \ projects \ partb \ partb \ partb.cpp (396): ошибка C3867: ‘std :: basic_string<_Elem, _Traits, _Ax> :: compare ‘: вызов функции отсутствует в списке аргументов; использовать&станд :: basic_string<_Elem, _Traits, _Ax> :: compare ‘для создания указателя на член с помощью [_Elem = char, _Traits = std :: char_traits, _Ax = std :: allocator]
1> partb.cpp (396): ошибка C2678: двоичный файл ‘==’: не найден оператор, который принимает левый операнд типа ‘std :: string’ (или нет приемлемого преобразования)
1> c: \ program files (x86) \ Microsoft Visual Studio 10.0 \ vc \ include \ exception (470): может быть ‘bool std :: operator == (const std :: _ Exception_ptr &, const std :: _ Exception_ptr &)»
1> c: \ программные файлы (x86) \ Microsoft Visual Studio 10.0 \ vc \ include \ exception (475): или ‘bool std :: operator == (std :: _ Null_type, const std :: _ Exception_ptr &)»
1> c: \ program files (x86) \ Microsoft Visual Studio 10.0 \ vc \ include \ exception (481): или ‘bool std :: operator == (const std :: _ Exception_ptr &, Станд :: _ Null_type)»
1> c: \ program files (x86) \ Microsoft Visual Studio 10.0 \ vc \ include \ system_error (408): или ‘bool std :: operator == (const std :: error_code &, const std :: error_condition &)»
1> c: \ program files (x86) \ Microsoft Visual Studio 10.0 \ vc \ include \ system_error (416): или ‘bool std :: operator == (const std :: error_condition) &, const std :: error_code &)»
1> при попытке сопоставить список аргументов ‘(std :: string, int)’
1
I get to help a lot of people learn C# programming every year. As I watch new developers grow and get used to working in C# and Visual Studio, it has become fairly clear to me that reading C# compiler errors and even their documentation is an acquired skill. I’ve made a request for Microsoft to improve the error message feedback in Visual Studio, but until that’s resolved developers still have a tough time working through early obstacles.
Because of this, I’m creating this unusual post to serve as beginner-friendly documentation to what I personally view as the most likely compiler errors a new developer is likely to encounter. Microsoft has wonderful documentation on compiler errors, and this is something that will help you out significantly as you grow, but early on a paragraph or two aimed at a beginner can be exactly what you need.
I also snuck in a few of the more interesting compiler errors I noticed about the maximum limits of the C# compiler, so even if you’re very familiar with C# at this point you’ll likely still learn a few things skimming this list.
Take a look at my list and my recommendations on these issues and let me know if you find this helpful or encounter something I missed.
CS0003 – Out of Memory
This occurs when a computer runs out of memory compiling your code. Close any unnecessary programs and reboot the machine if the problem persists.
CS0004 – Warning Treated as Error
Developers may configure projects to treat certain warnings as errors. These warnings may be specified in the build section of the project’s properties. Typically it is best to resolve the specific warning listed in the build errors since someone wanted that to be treated severely.
CS0015 – Type Name too Long
.NET requires the names of types and namespaces to be less than 1024 characters. If you find yourself getting this error, you may want to reconsider your team’s naming choices.
CS0017 – More than one entry point defined
This occurs when your program has more than one class defined with a static void main method. Remove one of them or manually set the project’s startup object in the project properties.
CS0019 – Operator ‘operator’ cannot be applied to operands of type ‘type’ and ‘type’
This occurs when you try to compare two different types in ways that cannot be compared. For example, checking to see if integer values are equal to Boolean values, subtracting a string from a number, etc. This error often occurs when developers forget what type of data is stored by a particular variable.
CS0020 – Division by Constant Zero
This occurs if you try to force a division by zero in your code. You cannot force a division by zero through a numeric literal or by using a constant for the denominator, but you can declare a variable holding 0 and use that as a denominator.
CS0021 – Cannot apply indexing to type
This occurs when you try to use an array or list-style indexer on a type that doesn’t support it. This often occurs when developers assume they’re working with an array, string, or list and are not.
CS0023 – Operator ‘operator’ cannot be applied to operand of type ‘type’
This occurs when you try to use a mathematical operator with a type that doesn’t support it. For example, trying to generate a negative value of a string. Double check that your variables are of the type you think they are and re-evaluate what you are trying to do.
CS0026 – Keyword this cannot be used in a static method
This error occurs when you are working inside of a static method and try to use the this keyword. Static methods are methods associated with the class itself and not with an instance of the class. As a result, static methods do not have access to any properties, methods, or fields on the class that are not static.
CS0029 – Cannot implicitly convert type ‘type’ to ‘type’
This occurs when you have a variable of one type and are trying to store it into a variable of another type. Some types allow you to automatically convert from one type to another (an implicit conversion), but the types you are using do not support that. You may need to use an explicit cast using (type) syntax.
CS0030 – Cannot convert type ‘type’ to ‘type’
This occurs when there is no implicit or explicit conversion between two different types. If you’re sure you need to do what you’re doing, you could create a method to convert from one type to the other.
CS0031 – Constant value ‘value’ cannot be converted to a ‘type’.
This occurs when you try to store a value into a variable type that cannot store that particular value. For example, if you try to store 5 billion into an integer (which can store values up to around 2.1 billion) you will get this compiler error. You can resolve this error by storing the value into a type that can hold larger values, such as a long.
CS0050 – Inconsistent accessibility: return type ‘type’ is less accessible than method ‘method’
This occurs when a method returns a type that has a visibility or access modifier that is more restrictive than the method and class the method is currently in. For example this error will occur if a public method in a public class returns a type that is defined as internal.
This error usually occurs when developers forget to mark a class as public. Remember that classes have a default access modifier of internal when no access modifier is specified. Typically the fix for this is to explicitly declare that class as public.
CS0051 – Inconsistent accessibility: parameter type ‘type’ is less accessible than method ‘method’
This occurs when a method takes in a parameter that is of a type that has a visibility or access modifier that is more restrictive than the method and class the method is currently in. For example this error will occur if a public method in a public class requires a parameter of a type that is defined as internal.
This error usually occurs when developers forget to mark a class as public. Remember that classes have a default access modifier of internal when no access modifier is specified. Typically the fix for this is to explicitly declare that class as public.
CS0052 – Inconsistent accessibility: field type ‘type’ is less accessible than field ‘field’
This occurs when a class has a public field that is of a type that has a visibility or access modifier that is more restrictive than the class the method is currently in. For example this error will occur if a class has a public field of a type that is defined as internal.
This error usually occurs when developers forget to mark a class as public. Remember that classes have a default access modifier of internal when no access modifier is specified. Typically the fix for this is to explicitly declare that class as public.
CS0053 – Inconsistent accessibility: property type ‘type’ is less accessible than property ‘property’
This occurs when a class has a property of a type that has a visibility or access modifier that is more restrictive than the property’s visibility. For example this error will occur if a public property is of a type that is defined as internal.
This error usually occurs when developers forget to mark a class as public. Remember that classes have a default access modifier of internal when no access modifier is specified. Typically the fix for this is to explicitly declare that class as public.
CS0060 – Inconsistent accessibility: base class ‘class1’ is less accessible than class ‘class2’
This occurs when a class inherits from another class but the subclass’s access modifier is less restrictive than the base class’s access modifier. For example this error will occur if a public class inherits from an internal class.
This error usually occurs when developers forget to mark a class as public. Remember that classes have a default access modifier of internal when no access modifier is specified. Typically the fix for this is to explicitly declare that class as public.
CS0061 – Inconsistent accessibility: base interface ‘interface 1’ is less accessible than interface ‘interface 2’
This occurs when an interface inherits from another interface but the child interface’s access modifier is less restrictive than the base interface’s access modifier. For example this error will occur if a public interface inherits from an internal interface.
This error usually occurs when developers forget to mark an interface as public. Remember that interfaces have a default access modifier of internal when no access modifier is specified, although every member of an interface is public. Typically the fix for this is to explicitly declare that interface as public.
CS0100 – The parameter name ‘parameter name’ is a duplicate
This occurs when a developer declares a method but uses the same parameter name twice in the method’s parameter list. The fix for this is generally to remove an unneeded parameter or to rename parameters so that all parameters have a different name.
CS0101 – The namespace ‘namespace’ already contains a definition for ‘type’
This occurs when a class is defined twice in the same namespace. This can occur when a class is renamed but the old file still exists, when a developer forgot to mark a class as part of a different namespace, or when a developer intended to use the partial keyword but forgot to specify it. The fix for this will vary based on which files you want and what namespaces they should live in.
CS0102 – The type ‘type name’ already contains a definition for ‘identifier’
This occurs when you declare a member such as a field twice in the same class. Often this is a symptom of using an existing variable name instead of choosing a new name.
CS0103 – The name ‘identifier’ does not exist in the current context
This error often occurs when trying to use a variable defined in another scope. This commonly occurs when you try to define a variable inside of a try block and refer to it in a catch block, when there was no guarantee that the runtime was able to create that variable and therefore the variable is not available.
The fix for this is typically to declare the variable before the try / catch block and update its value from the try block. In this way the catch block will get either the initial value of the variable or its updated value and will be able to reference it.
CS0111 – Type ‘class’ already defines a member called ‘member’ with the same parameter types
This occurs when a developer creates a duplicate method or property with an identical signature consisting of a return type and parameter types. The compiler detects that there will not be a way for code outside of the class to distinguish between one member and the other and so this error is raised. Typically when this occurs you need to either rename one of the two members, change the parameters of one of the methods, or merge the two methods together into one method.
CS0117 – ‘type’ does not contain a definition for ‘identifier’
This occurs when you are trying to call a method or use a property on an instance of an object, but there is no method or property with that name. This can be an issue with capitalization, spelling, or forgetting the name of the member you’re referring to. Code completion can help you find the correct name to use.
CS0120 – An object reference is required for the non-static field, method, or property ‘member’
This often occurs in static methods when you attempt to work with non-static members of the same class. Remember that static methods are associated with the class itself and not with a specific instance of that class. As a result, static methods cannot access properties, fields, and methods that are not marked as static.
The fix for this is often to remove the static keyword from the method that needs to access instance variables. This is counter-intuitive since the compiler pushes you towards adding static in other places, but if you follow that path to its logical conclusion all of your data becomes static eventually, so you’re better off removing the static keyword when confronted by this.
CS0122 – ‘member’ is inaccessible due to its protection level
This occurs when you are trying to call a method or use a property on an instance of an object, but that member is defined as private or protected and you are outside of the class or something that inherits from it. You may not be intended to work with the method or property you are using and you should probably look for public members that might meet your needs without compromising the class’s encapsulation.
CS0127 – Since ‘function’ returns void, a return keyword must not be followed by an object expression
This is a rarer error that occurs when you are in a method defined as void but are trying to return a specific object. Remember that void methods do not return any value so a return statement should just be listed as return;. If you find that you do need to return a value, you should change the return type of the method from void to some specific type.
CS0128 – A local variable named ‘variable’ is already defined in this scope
This occurs when you re-declare a variable that already exists. The solution for this is to either use a different variable name or to remove the type name from your statement and change it from a variable declaration to an assignment statement and re-use the existing variable.
This error often comes from copying and pasting code that declares a new variable.
CS0133 – The expression being assigned to ‘variable’ must be constant
This occurs when you are declaring a const and declaring it to another variable. Constants are evaluated at the time your code is compiled and the compiler will not know the value of your variables. As a result, constants must be set to a literal number or string value.
CS0134 – ‘variable’ is of type ‘type’. A const field of a reference type other than string can only be initialized with null.
This occurs when you are trying to declare a const of a type other than a numeric or string value. Typically, if you have a const that needs to store a reference type you should instead use readonly which is less optimized than a const but works with reference types and ensures that the value will never change.
CS0136 – A local variable named ‘var’ cannot be declared in this scope because it would give a different meaning to ‘var’, which is already used in a ‘parent or current/child’ scope
This occurs when you declare a new variable with the same name as another variable in a visible scope. The solution for this is to either use a different variable name or to remove the type name from your statement and change it from a variable declaration to an assignment statement and re-use the existing variable.
CS0145 – A const field requires a value to be provided
This occurs when you declare a const but do not provide a value. You should set a const equal to some string or numeric variable when declaring it.
CS0150 – A constant value is expected
This occurs when the compiler requires a constant value such as a numeric or string literal but a variable is defined. This can occur when you use a variable in a switch statement or when you are using an array initializer for an array with a variable size.
Switch statements cannot use cases for specific variables, though switch expressions are more flexible.
When working with arrays of varying size, you may want to avoid the use of array initializers and instead manually set the elements of the array after creation.
CS0152 – The label ‘label’ already occurs in this switch statement
This occurs when you duplicate a case statement inside of a switch statement. Typically this occurs when you didn’t notice the case already existed and you can delete your repeated case statement.
CS0160 – A previous catch clause already catches all exceptions of this or of a super type (‘type’)
The ordering of catch statements in a try / catch matters since the runtime will try to match the first catch that applies to the exception it encountered. Because of this, the compiler generates this error if it sees a more specific exception type after a less specific exception type since this results in a case where the more specific catch statement could never be reached.
Move your more specific catch statement above the less specific one to fix this error.
CS0161 – Not all code paths return a value
This occurs because the C# compiler believes that it is possible to get to the end of your method without encountering a return statement. Keep in mind that the C# compiler does very little inferences based on your if statements and even if it may not actually be possible to reach the end of the method without returning, the compiler still thinks it is.
The fix for this is almost always to add a final return statement.
CS0165 – Use of unassigned local variable
This occurs when the compiler sees a variable that is defined but not set to an initial value and determines that the value of that variable needs to be read from later on in the method before the variable is guaranteed to have its value set.
The fix for this is generally to set the variable to be equal to an initial value.
CS0176 – Static member ‘member’ cannot be accessed with an instance reference; qualify it with a type name instead
This occurs when you have a static property or field on a class but are trying to refer to it on a specific instance of that class.
Use the class name instead of the instance variable to access the static member.
CS0201 – Only assignment, call, increment, decrement, and new object expressions can be used as a statement
This typically occurs when you are performing some sort of mathematical operation but not storing the result into a variable. The compiler understands the operation but sees it has no value, so it raises the error.
The fix for this is to store the result of the mathematical operation into a variable or to remove the unnecessary line.
CS0204 – Only 65534 locals are allowed
Apparently you have a method that has over 65 thousand local variables inside of it. The compiler doesn’t like this very much and, frankly, I’m a little concerned why you’d need that many.
Reconsider your life choices.
CS0230 – Type and identifier are both required in a foreach statement
This occurs when you are writing a foreach statement without specifying all parts of the statement.
foreach statements require a variable type, a variable name, the word in, and some variable that can be enumerated over. For example: foreach (string person in people)
CS0234 – The type or namespace name ‘name’ does not exist in the namespace ‘namespace’ (are you missing an assembly reference?)
This occurs when you are trying to refer to a type via its fully-qualified name, including the namespace, but no known type exists with that namespace and type name. This can be a spelling error, a mistake as to which namespace the type lives in, or a correct namespace and type, but your project does not yet have a reference to the project the type is defined in.
If your spelling and namespaces are correct you may need to add a project reference to your project or install a package via nuget.
CS0236 – A field initializer cannot reference the non-static field, method, or property ‘name’.
This occurs when you try to define a field by referencing another field. This error exists to prevent unpredictable behavior based on which field initializers run first.
The fix for this is to set the value of the field in the constructor instead of in a field initializer.
CS0246 – The type or namespace name ‘type/namespace’ could not be found (are you missing a using directive or an assembly reference?)
This occurs when you are trying to refer to a type no known type exists with that type name in the using statements currently in your file.
This is usually a spelling error or a missing using statement at the top of your file.
If your spelling and using statements are correct you may need to add a project reference to your project or install a package via nuget.
CS0266 – Cannot implicitly convert type ‘type1’ to ‘type2’. An explicit conversion exists (are you missing a cast?)
This occurs when you are trying to store a variable of one type into a variable of another type without casting. For example, if you are trying to set a double value into an int variable you will see this error.
The statement “an explicit conversion exists (are you missing a cast)” is telling you that these types are compatible, but the compiler wants to make sure you intend to convert from one to another so it requires you to cast your variable from one type to another.
You cast variables in C# by using parentheses around a type name like this: int num = (int)myDouble;
CS0500 – ‘class member’ cannot declare a body because it is marked abstract
This occurs when you declare an abstract member inside of an abstract class, but you tried to give it a method body (using {}). Abstract members do not have method bodies.
Remove the {}’s from your abstract method. Alternatively, if you want to provide a default implementation and allow inheriting classes to optionally override yours, use virtual instead of abstract.
CS0501 – ‘member function’ must declare a body because it is not marked abstract, extern, or partial
This occurs when you try to declare a method but forget to give it a method body with {}’s.
This can also occur when you mean to define an abstract method but forgot to use the abstract keyword.
CS0506 – ‘function1’ : cannot override inherited member ‘function2’ because it is not marked “virtual”, “abstract”, or “override”
In C# you have to mark a method as virtual or abstract to be able to override it.
The fix for this is usually to add the virtual keyword to the method in the base class.
CS0507 – ‘function1’ : cannot change access modifiers when overriding ‘access’ inherited member ‘function2’
When overriding a method you must keep the same access modifier as the base method. If the access modifier needs to change, change it in all classes that have the method.
CS0508 – ‘Type 1’: return type must be ‘Type 2’ to match overridden member ‘Member Name’
When overriding a method you cannot change the return type of the method. If you think you need to return something radically different, you may need to introduce a new method instead of overriding an existing one. Alternatively, creative uses of interfaces or inheritance can allow you to return a more specific version of something from a method through polymorphism.
CS0513 – ‘function’ is abstract but it is contained in nonabstract class ‘class’
When you need a method to be abstract, the entire class needs to be abstract as well.
CS0525 – Interfaces cannot contain fields
This one is self-explanatory. An interface is a contract that defines what members need to be present. Fields in classes should be private and are implementation details that do not belong in an interface.
CS0526 – Interfaces cannot contain constructors
This one is self-explanatory. An interface is a contract that defines what members need to be present on an already-constructed class. Interfaces do not care about how an instance is created and cannot denote constructors required for a given class.
CS0531 – ‘member’ : interface members cannot have a definition
This occurs when you try to give an interface member a method body. Interfaces denote capabilities that must be in place, not how those capabilities should work.
If you think you really need a default implementation of a method, you might want to use an abstract class instead of an interface.
CS0534 – ‘function1’ does not implement inherited abstract member ‘function2’
This occurs when you inherit from an abstract class that has abstract members but do not override those members. Because of this, the compiler has no implementation for those abstract members and does not know how to handle them if they are called.
Override the inherited member or mark the inheriting class as abstract as well.
CS0535 – ‘class’ does not implement interface member ‘member’
This occurs when you implement an interface but have not provided members that match those defined in the interface. Members must match the exact type signatures of those defined in the interface and should have names that match those in the interface as well.
CS0645 – Identifier too long
This occurs when you try to name a variable or other identifier something longer than 512 letters long.
What exactly are you trying to do over there that has you naming variables this long?
CS0844 – Cannot use local variable ‘name’ before it is declared.
This occurs when you try to use a variable in a method above when that variable is declared. C# does not have hoisting like some other languages do and variables are only available after they are declared.
Reorder your statements to match your needs.
CS1001 – Identifier expected
This usually occurs when you forget the name of a variable, class, or parameter but have defined other aspects of that line of code. Check some reference materials for what you are trying to do because you’re missing something important.
CS1002 – Semicolon expected
C# requires you to end most statements with a semicolon, including this one. Add a semicolon to the end of the line and all should be well.
CS1026 – ) expected
You have too many opening parentheses and not enough closing parentheses. Check to make sure that all open-parentheses have a matching closing parentheses.
Clicking on a parentheses in Visual Studio will highlight the matching parentheses making it easier to spot the one you’re missing.
CS1033 – Source file has exceeded the limit of 16,707,565 lines representable in the PDB; debug information will be incorrect
What on earth are you even doing over there? Why would you have a source file that requires more than 16 million lines?
Don’t do that. Just no. It’s time to hire a consultant.
CS1034 – Compiler limit exceeded: Line cannot exceed ‘number’ characters
Some people like tabs. Some people like spaces. You, apparently solve this debate by removing line breaks entirely.
You should never need to have a line of code longer than 16 million characters.
CS1035 – End-of-file found, ‘*/’ expected
Your code has a block comment start (/*) but no matching end comment. Add an end comment (*/) and the compiler will be happier.
CS1039 – Unterminated string literal
It looks like you started a string somewhere but forgot to put the other quotation mark. Add it in where it needs to be.
CS1501 – No overload for method ‘method’ takes ‘number’ arguments
This occurs when you are trying to call a method with an incorrect number of arguments or parameters to that method. Check the code or documentation for the method you’re trying to call and ensure you have the correct number of arguments specified.
CS1513 – } expected (missing closing scope)
You have too many opening curly braces and not enough closing curly braces. Check to make sure that all open curly braces have a matching closing curly brace.
Clicking on a { in Visual Studio will highlight the matching } making it easier to spot the one you’re missing.
CS1514 – { expected
Your code requires a { but you didn’t provide one. This often happens after declaring a namespace or class. Check your syntax and add curly braces where they need to go.
CS1525 – Invalid expression term ‘character’
This error seems ambiguous, but most of the time when I see this error it comes from someone trying to use == to assign a value to a variable instead of using the = operator. If this is not your error, you may need to consult some documentation or reference material for valid syntax for what you’re trying to do.
CS1552 – Array type specifier, [], must appear before parameter name
This error occurs when you put [] syntax around the variable name and not around the type name when declaring an array.
Write your arrays as int[] myArray; instead of int myArray[];.
CS1604 – Cannot assign to ‘variable’ because it is read-only
This occurs when you’ve declared a readonly or const variable and are trying to set its value. You can’t do that. If you need to change its value, it can’t be readonly or const.
CS7036 – No argument given that corresponds to the required formal parameter (incorrect method call)
This error occurs when trying to call a base constructor but not specifying a parameter that is required by that constructor.
Double check your base() call and make sure the number and types of parameters lines up with a specific constructor present on your base class.
Published August 30, 2019
As explained in item 53 of Effective C++, you should “Pay attention to compiler warnings”. In the vast majority of cases, the compiler has a good reason to emit them, and in the vast majority of cases, they point out to an oversight in your code.
But in a minority of cases, you may want to deliberately write code that triggers a warning.
In such occasions, letting the warning in the compiler’s output has several drawbacks. First, you will no longer have a clean build with no errors and no warnings. This warning will always remain here, and you’ll have to check that it’s the one you decided to leave in every time you compile the code.
This doesn’t scale if there are several warnings you decide to leave, because at each build you’ll have to check them all to see if a new warning hasn’t popped up and needs to be checked.
Second, if you’re following the best practice of transforming warnings into errors, by activating the -Werror flag in gcc and clang for example, leaving a warning in is simply not an option.
Fortunately, C++ lets you block the emission of a specific warning for a portion of code. Let’s see how to do that and keep code expressive.
Different code for different compilers
Let’s take the example of the warning that warns you that you didn’t use one of the parameters of a function:
void f(int a, int b)
{
std::cout << a << '\n';
// we are not using b!
}
The compiler is able to emit a warning for this. But all compilers don’t emit the same warning.
Here is gcc’s warning, which is the same as clang’s:
warning: unused parameter 'b' [-Wunused-parameter]
And here is Visual Studio’s warning:
warning C4100: 'b': unreferenced formal parameter
You can observe that they don’t have the same text and–more importantly for our purpose–the warning is not identified the same way.
Visual Studio identifies warnings with a number (here, 4100), whereas gcc and clang use a string (here, -Wunused-parameter).
As you can imagine, that will lead to different code to disable the same warning between the compilers.
We’re going to see how to disable a warning on gcc, clang, and on Visual Studio, and in case your application has to compile on all three, how to write code that disable a warning on all compilers.
The disabling sequence
Before we get into the code for each compiler, there is something in common in the sequence of disabling a warning between all three compilers.
To disable a set of warnings for a given piece of code, you have to start with a “push” pre-processor instruction, then with a disabling instruction for each of the warning you want to suppress, and finish with a “pop” pre-processor instruction.
For example, in our case, the sequence would look like that:
// up until this line, the warning is active
// PUSH disable warning (instruction specific to the compiler, see below)
// DISABLE the warning that a parameter is not used
void f(int a, int b)
{
std::cout << a << '\n';
// we are not using b, but the compiler won't emit a warning
}
// POP disable warning, the warning is now active again
Now let’s dive into the code for each compiler.
Disabling a warning on gcc and clang
A good thing is that gcc and clang require the exact same code for disabling a warning, as far as I’m aware.
The push instruction is this:
#pragma GCC diagnostic push
Note that even though it says “GCC”, it also works for clang.
The pop instruction is this:
#pragma GCC diagnostic pop
And to disable a warning, you indicate it this way:
#pragma GCC diagnostic ignored "-Wunused-parameter"
Putting this together, to suppress the warning in our example code we write:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
void f(int a, int b)
{
std::cout << a << '\n';
// we are not using b!
}
#pragma GCC diagnostic pop
That’s is for gcc and clang.
Disabling a warning on Visual Studio
With Visual Studio, the push instruction is this:
#pragma warning( push )
The pop instruction is this:
#pragma warning( pop )
And to disable a specific warning, we need to write code like this:
#pragma warning( disable : 4100 )
Remember, in Visual Studio warnings are identified with numbers, not names.
If we have to suppress the warning in our example code on Visual Studio, we would write this:
#pragma warning( push )
#pragma warning( disable : 4100 )
void f(int a, int b)
{
std::cout << a << '\n';
// we are not using b!
}
#pragma warning( pop )
All in all, this is not so complicated.
But what if you write code that needs to compile on gcc, clang AND Visual Studio?
That can happen if your application is deployed on multiple OSes, or if you write a library for the general population of C++ programmers.
This is where the fun begins.
Disabling a warning on gcc, clang and Visual Studio at the same time
Since disabling warnings is done at the level of the pre-processor, we’re going to need a macro. We need to write a macro that resolves to either one of the above pieces of code, depending on the compiler used.
The disabling sequence is similar between all three compilers, so we’ll write a macro for each of the three steps: push, disable and pop:
DISABLE_WARNING_PUSH
DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER
void f(int a, int b)
{
std::cout << a << '\n';
// we are not using b!
}
DISABLE_WARNING_POP
Let’s see how to write each macro on the various compilers, and then how to write code to combine all this into a cross-compiler code. We’re going to have some macro fun.
Implementing the macros on gcc and clang
As we saw above, the push in gcc and clang is this:
#pragma GCC diagnostic push
Our first instinct could be to define the DISABLE_WARNING_PUSH like this:
#define PIPES_DISABLE_WARNING_PUSH #pragma(GCC diagnostic push)
But using DISABLE_WARNING_PUSH then fails to compile:
error: expected unqualified-id DISABLE_WARNING_PUSH ^ note: expanded from macro 'DISABLE_WARNING_PUSH' #define DISABLE_WARNING_PUSH #pragma(GCC diagnostic push)
It’s because we’re not allowed to use #pragma in a #define instruction.
To circumvent this problem, compilers commonly offers a “pragma operator”, that is not standard and differs across compilers.
In gcc and clang, it is called _Pragma, and can be used this way:
#define DISABLE_WARNING_PUSH _Pragma("GCC diagnostic push")
Note that _Pragma expects a string with quotes, hence the "GCC diagnostic push".
Similarly, the pop instruction is this:
#define DISABLE_WARNING_POP _Pragma("GCC diagnostic pop")
Now to disable the warning, we have to write this:
#define DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER _Pragma("GCC diagnostic ignored \"-Wunused-parameter\"")
Note the \" around the name of the warning. Remember that gcc and clang identify warning with strings, and that _Pragma expects a string. This results in a string within a string, so quotes inside of quotes, which then need to be escaped.
This is not pretty. To mitigate this, we could use C++11’s raw strings literals:
#define DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER _Pragma(R"(GCC diagnostic ignored "-Wunused-parameter")")
But this is still far from ideal. Especially if we want to disable several types of warnings, because we’d need to repeat this code over and over.
What would be nice would be to write this:
#define DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER DISABLE_WARNING(-Wunused-parameter)
With no quotes, just the name of the warning.
Let’s see how to do that. This where the macro fun begins.
Generic macro code
To get rid of all the issues with quotes, we’re going to use the “Stringizing opeator”, which is #. As Microsoft Docs puts it, “If [the stringizing opeator] precedes a formal parameter in the macro definition, the actual argument passed by the macro invocation is enclosed in quotation marks and treated as a string literal.”
Put another way, the # operator puts quotes around a macro parameter.
The stringizing operator helps support the DO_PRAGMA trick, that consists in defining the following macro:
#define DO_PRAGMA(X) _Pragma(#X)
In short, DO_PRAGMA puts quotes around a string and passes it to the _Pragma operator.
We’re going to use it this way (we’ll see how that works step by step afterwards):
#define DISABLE_WARNING(warningName) \
DO_PRAGMA(GCC diagnostic ignored #warningName)
DISABLE_WARNING is a macro function that takes a parameter, which we can invoke like this:
DISABLE_WARNING(-Wunused-parameter)
In this case, warningName is -Wunused-parameter. So #warningName, with the stringizing operator, is "-Wunused-parameter".
Thus,
GCC diagnostic ignored #warningName
is equivalent to
GCC diagnostic ignored "-Wunused-parameter"
Finally, DO_PRAGMA(GCC diagnostic ignored #warningName) puts quotes around all that and sends it to _Pragma. Which leads to the desired result.
As a result, this macro function allows to disable several warnings with expressive code:
#define DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER DISABLE_WARNING(-Wunused-parameter) #define DISABLE_WARNING_UNREFERENCED_FUNCTION DISABLE_WARNING(-Wunused-function) // and so on
Implementing the macro in Visual Studio
If you came out of the preceding section in one piece, the rest should glide.
Visual Studio follows the same principles as gcc and clang: you can’t put a #pragma inside of a #define directive, but there is a pragma operator to help us achieve this. But contrary to gcc, it is not called _Pragma but __pragma, with two underscores.
What’s easier in Visual Studio than in gcc and clang is that the warnings are not identified by strings but by numbers (e.g. 4100), and the __pragma operator doesn’t expect strings in quotes.
So here is how to write DISABLE_WARNING for Visual Studio:
#define DISABLE_WARNING(warningNumber) __pragma(warning( disable : warningNumber ))
The push and the pop are also straightforward:
#define DISABLE_WARNING_PUSH __pragma(warning( push )) #define DISABLE_WARNING_POP __pragma(warning( pop ))
Putting it all together
Now that we know how to disable a warning for gcc, clang and Visual Studio, let’s put this altogether in the same code, so that your application or library can run on all three compilers with the same code.
Essentially, the code is going to follow this structure:
if Visual Studio
code for Visual Studio
else if gcc or clang
code for gcc and clang
else
macros that are defined but don't do anything
To identity the compiler, we can rely on the specific macro that each of them defines:
_MSC_VERfor Visual Studio (which incidentally also gives the version of the compiler, but we won’t use this information),__GNUC__for gcc,__clang__for clang.
You’ll note that they use the naming convention that C++ programmers are not allowed to use: two consecutive underscores, and a name starting with an underscore followed by a capital letter. The very reason why we can’t use them is because they are reserved to the compiler. Like here.
Note the else part in the above code. I think it is necessary to define the same macros as in the if and else if branches. Even if you don’t use another compiler than Visual Studio, gcc or clang today, it would be a shame to halt the compilation on another compiler just because you didn’t define the macros for it.
Or perhaps you don’t want your code to run on a compiler you don’t officially support. In any case, if this is what you want then a better option is to write somewhere else some specific macro-code to prevent the code from compile on non-supported compilers.
In summary, here is all the code put together:
#if defined(_MSC_VER)
#define DISABLE_WARNING_PUSH __pragma(warning( push ))
#define DISABLE_WARNING_POP __pragma(warning( pop ))
#define DISABLE_WARNING(warningNumber) __pragma(warning( disable : warningNumber ))
#define DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER DISABLE_WARNING(4100)
#define DISABLE_WARNING_UNREFERENCED_FUNCTION DISABLE_WARNING(4505)
// other warnings you want to deactivate...
#elif defined(__GNUC__) || defined(__clang__)
#define DO_PRAGMA(X) _Pragma(#X)
#define DISABLE_WARNING_PUSH DO_PRAGMA(GCC diagnostic push)
#define DISABLE_WARNING_POP DO_PRAGMA(GCC diagnostic pop)
#define DISABLE_WARNING(warningName) DO_PRAGMA(GCC diagnostic ignored #warningName)
#define DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER DISABLE_WARNING(-Wunused-parameter)
#define DISABLE_WARNING_UNREFERENCED_FUNCTION DISABLE_WARNING(-Wunused-function)
// other warnings you want to deactivate...
#else
#define DISABLE_WARNING_PUSH
#define DISABLE_WARNING_POP
#define DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER
#define DISABLE_WARNING_UNREFERENCED_FUNCTION
// other warnings you want to deactivate...
#endif
You can then use the macros this way:
DISABLE_WARNING_PUSH DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER DISABLE_WARNING_UNREFERENCED_FUNCTION /* code where you want to disable the warnings */ DISABLE_WARNING_POP
A great responsibility
This leads to code that is both concise and portable across compilers. Indeed, if you need to support a new compiler, you can just add a new branch to the #if defined statement.
But before you get into all this, heed the advice of Effective C++ and “Pay attention to compiler warnings.” Only once you did that, and if you know what you’re doing, use the above code to silence a warning in a portion of your code.
You will also like
- What Books to Read to Get Better In C++
- How to split a string in C++
- Better Macros, Better Flags
- 3 Types of Macros That Improve C++ Code
- TODO_BEFORE(): A Cleaner Codebase for 2019
Don’t want to miss out ? Follow:
Share this post!
Эти сообщения об ошибках
1.For the Visual Studio compiler: error C2065: 'printf' : undeclared identifier
2.For the GCC compiler: `printf' undeclared (first use in this function)
означает, что вы используете имя printf, но компилятор не видит, где было объявлено имя и, соответственно, не знает, что это значит.
Любое имя, используемое в программе, должно быть объявлено до его использования. Компилятор должен знать, что означает это имя.
В этом конкретном случае компилятор не видит объявления с именем printf. Как мы знаем (но не компилятор), это имя стандартной функции C, объявленной в заголовке <stdio.h> в C или в заголовке <cstdio> в С++, и помещается в стандартную (std::) и глобальную (::) ( не обязательно) пространства имен.
Поэтому перед использованием этой функции мы должны предоставить объявление своего имени компилятору, включив соответствующие заголовки.
Например
С
#include <stdio.h>
int main( void )
{
printf( "Hello World\n" );
}
С++:
#include <cstdio>
int main()
{
std::printf( "Hello World\n" );
// or printf( "Hello World\n" );
// or ::printf( "Hello World\n" );
}
Иногда причиной такой ошибки является простая опечатка. Например, допустим, что вы определили функцию PrintHello
void PrintHello()
{
std::printf( "Hello World\n" );
}
но в основном вы сделали опечатку, а вместо PrintHello вы набрали PrintHello строчной буквой «p».
#include <cstdio>
void PrintHello()
{
std::printf( "Hello World\n" );
}
int main()
{
printHello();
}
В этом случае компилятор выдает такую ошибку, потому что не видит объявления имени PrintHello. PrintHello и PrintHello — это два разных имени, одно из которых было объявлено, а другое не было объявлено, а использовано в теле основного
