Выбор реализаций функций C ++ с использованием компоновщика - PullRequest
0 голосов
/ 15 ноября 2018

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

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

Ниже приведен простой пример, демонстрирующий идею.

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

#include <iostream>

using namespace std;

// model teacher program : main calls g which calls f

int f(int x) {
  cout << "in teacher-f(" << x << ")" << endl;
  return 46;
}

int g(int x) {
  cout << "in teacher-g(" << x << ")" << endl;
  int y = f(x);
  cout << "f(" << x << ") returned " << y << endl;  
  return 91;  
}

int main() {
  cout << "in teacher-main()" << endl;
  int x = 2;
  int y = g(x);
  cout << "g(" << x << ") returned " << y <<  endl;  
}

Типичный код студента, пытающийся соответствовать тем же спецификациям, который необходимо протестировать.В моем случае это "main", несколько #includes и "using namespace std;"можно было бы ожидать.

#include <iostream>

using namespace std;

// model student program : main calls g which calls f

int f(int x) {
  cout << "in student-f(" << x << ")" << endl;
  return 27;
}

int g(int x) {
  cout << "in student-g(" << x << ")" << endl;
  int y = f(x);
  cout << "f(" << x << ") returned " << y << endl;  
  return 82;  
}

int main() {
  cout << "in student-main()" << endl;
  int x = 4;
  int y = g(x);
  cout << "g(" << x << ") returned " << y <<  endl;  
  return 0;
}

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

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

g++ -c student.cpp
# (this makes student.o)
# strip f() and main() from student.o:
strip -N main -N _Z1fi student.o

# similarly for teacher, but stripping g
g++ -c teacher.cpp
strip -N _Z1gi teacher.o
g++ -o final teacher.o student.o
./final

и ожидаемый результат будет

in teacher-main()
in student-g(2)
in teacher-f(2)
f(2) returned 46
g(4) returned 82

, к сожалению, я получаю:

strip: not stripping symbol `_Z1fi' because it is named in a relocation

Я пытался сделать что-то подобное с .soбиблиотеки вместо.Сообщение об ошибке «раздеться» исчезает, но, к сожалению, на этот раз учитель звонит учителю, которого я пытался удалить.

g++ -shared -fPIC -o student.so student.cpp
g++ -shared -fPIC -o teacher.so teacher.cpp 
strip -N main -N _Z1fi student.so
strip -N _Z1gi  teacher.so
g++ -o final teacher.so student.so
./final

, давая

in teacher-main()
in teacher-g(2)
in teacher-f(2)
f(2) returned 46
g(2) returned 91

Есть предложения?Это вообще возможно?Если нет, есть ли способ сделать то же самое?Как я уже сказал, я не могу редактировать student.cpp, но я могу #include его из другого исходного кода.

Спасибо Ричард

Ответы [ 3 ]

0 голосов
/ 15 ноября 2018

Я думаю, что единственное возможное решение - разделить его на два файла:

1-й файл должен быть общим для учителя и ученика и может содержать как main, так и f + предварительную декларацию для g:

общий файл: (common.cpp)

#include <iostream>    
using namespace std;
int g(int x) ;

int f(int x) {
  cout << "in teacher-f(" << x << ")" << endl;
  return 46;
}

int main() {
  cout << "in teacher-main()" << endl;
  int x = 2;
  int y = g(x);
  cout << "g(" << x << ") returned " << y <<  endl;  
}

2-й файл должен содержать метод g (+ прямое объявление f):

teacher(teacher.cpp):

#include <iostream>
using namespace std;
int f(int x);

int g(int x) {
  cout << "in teacher-g(" << x << ")" << endl;
  int y = f(x);
  cout << "f(" << x << ") returned " << y << endl;  
  return 91;  
}

student (student.cpp):

#include <iostream>
using namespace std;
int f(int x);

int g(int x) {
  cout << "in student-g(" << x << ")" << endl;
  int y = f(x);
  cout << "f(" << x << ") returned " << y << endl;  
  return 82;  
}

теперь вы можете скомпилировать учителя из common.cpp + teacher.cpp

g++ -o teacher common.cpp teacher.cpp

и студент из common.cpp + student.cpp

g++ -o student common.cpp student.cpp

The common.cpp может быть даже заменен статической или общей библиотекой, и вы можете добавить заголовок вместо прямого объявления f.

0 голосов
/ 15 ноября 2018

Это было от Лоуренса и отвечает на мой вопрос.Я не могу сказать о мобильности и т. Д.

g++ -c student.cpp
g++ -c teacher.cpp 
strip -N main student.o
objcopy -W _Z1fi student.o
objcopy -W _Z1gi  teacher.o
g++ -o final teacher.o student.o
./final

даёт ожидаемое

in teacher-main()
in student-g(2)
in teacher-f(2)
f(2) returned 46
g(2) returned 82

Спасибо!

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

0 голосов
/ 15 ноября 2018

Это несколько нарушает ваши требования, но я бы посоветовал вам изменить ожидаемую форму студенческого кода. Не требуйте, чтобы они кодировали main, или попросите затем кодировать main в отдельном модуле компиляции, или просто попросите их переименовать их main, чтобы сказать main_ перед отправкой. Или просто добавьте #define main main_ в начало кода студента после представления перед компиляцией; для простых задач этого будет достаточно.

После этого вам не нужно ничего убирать из скомпилированного кода. Просто поместите все ваши функции в namespace teacher, напишите свой собственный main, который будет выполнять всю необходимую работу, и свяжите весь код вместе. Измените и перекомпилируйте код, чтобы он вызывал teacher::f для вашей функции или ::f для функции учащегося.

...