2013-04-18 14 views
6

Obecnie próbuję zrozumieć, jak działa poniższy kod (http://pastebin.com/zTHUrmyx), moje podejście polega obecnie na kompilacji oprogramowania w debugowaniu i użyciu gdb do przejrzenia kodu.Zrozumienie niektórych praktyk kodowania w C++

Jednak mam problem, że "krok" nie zawsze mówi mi, co się dzieje. Szczególnie niezrozumiałe jest dla mnie EXECUTE {...}, do którego nie mogę się zbliżyć.

Jak mogę się dowiedzieć, co robi kod?

1  /* 
    2  Copyright 2008 Brain Research Institute, Melbourne, Australia 
    3 
    4  Written by J-Donald Tournier, 27/06/08. 
    5 
    6  This file is part of MRtrix. 
    7 
    8  MRtrix is free software: you can redistribute it and/or modify 
    9  it under the terms of the GNU General Public License as published by 
    10  the Free Software Foundation, either version 3 of the License, or 
    11  (at your option) any later version. 
    12 
    13  MRtrix is distributed in the hope that it will be useful, 
    14  but WITHOUT ANY WARRANTY; without even the implied warranty of 
    15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
    16  GNU General Public License for more details. 
    17 
    18  You should have received a copy of the GNU General Public License 
    19  along with MRtrix. If not, see <http://www.gnu.org/licenses/>. 
    20 
    21 
    22  15-10-2008 J-Donald Tournier <[email protected]> 
    23  * fix -prs option handling 
    24  * remove MR::DICOM_DW_gradients_PRS flag 
    25 
    26  15-10-2008 J-Donald Tournier <[email protected]> 
    27  * add -layout option to manipulate data ordering within the image file 
    28 
    29  14-02-2010 J-Donald Tournier <[email protected]> 
    30  * fix -coord option so that the "end" keyword can be used 
    31 
    32 
    33 */ 
    34 
    35 #include "app.h" 
    36 #include "image/position.h" 
    37 #include "image/axis.h" 
    38 #include "math/linalg.h" 
    39 
    40 using namespace std; 
    41 using namespace MR; 
    42 
    43 SET_VERSION_DEFAULT; 
    44 
    45 DESCRIPTION = { 
    46 "perform conversion between different file types and optionally extract a subset of the input image.", 
    47 "If used correctly, this program can be a very useful workhorse. In addition to converting images between different formats, it can be used to extract specific studies from a data set, extract a specific region of interest, flip the images, or to scale the intensity of the images.", 
    48 NULL 
    49 }; 
    50 
    51 ARGUMENTS = { 
    52 Argument ("input", "input image", "the input image.").type_image_in(), 
    53 Argument ("ouput", "output image", "the output image.").type_image_out(), 
    54 Argument::End 
    55 }; 
    56 
    57 
    58 const gchar* type_choices[] = { "REAL", "IMAG", "MAG", "PHASE", "COMPLEX", NULL }; 
    59 const gchar* data_type_choices[] = { "FLOAT32", "FLOAT32LE", "FLOAT32BE", "FLOAT64", "FLOAT64LE", "FLOAT64BE", 
    60  "INT32", "UINT32", "INT32LE", "UINT32LE", "INT32BE", "UINT32BE", 
    61  "INT16", "UINT16", "INT16LE", "UINT16LE", "INT16BE", "UINT16BE", 
    62  "CFLOAT32", "CFLOAT32LE", "CFLOAT32BE", "CFLOAT64", "CFLOAT64LE", "CFLOAT64BE", 
    63  "INT8", "UINT8", "BIT", NULL }; 
    64 
    65 OPTIONS = { 
    66 Option ("coord", "select coordinates", "extract data only at the coordinates specified.", false, true) 
    67  .append (Argument ("axis", "axis", "the axis of interest").type_integer (0, INT_MAX, 0)) 
    68  .append (Argument ("coord", "coordinates", "the coordinates of interest").type_sequence_int()), 
    69 
    70 Option ("vox", "voxel size", "change the voxel dimensions.") 
    71  .append (Argument ("sizes", "new dimensions", "A comma-separated list of values. Only those values specified will be changed. For example: 1,,3.5 will change the voxel size along the x & z axes, and leave the y-axis voxel size unchanged.") 
    72   .type_sequence_float()), 
    73 
    74 Option ("datatype", "data type", "specify output image data type.") 
    75  .append (Argument ("spec", "specifier", "the data type specifier.").type_choice (data_type_choices)), 
    76 
    77 Option ("scale", "scaling factor", "apply scaling to the intensity values.") 
    78  .append (Argument ("factor", "factor", "the factor by which to multiply the intensities.").type_float (NAN, NAN, 1.0)), 
    79 
    80 Option ("offset", "offset", "apply offset to the intensity values.") 
    81  .append (Argument ("bias", "bias", "the value of the offset.").type_float (NAN, NAN, 0.0)), 
    82 
    83 Option ("zero", "replace NaN by zero", "replace all NaN values with zero."), 
    84 
    85 Option ("output", "output type", "specify type of output") 
    86  .append (Argument ("type", "type", "type of output.") 
    87   .type_choice (type_choices)), 
    88 
    89 Option ("layout", "data layout", "specify the layout of the data in memory. The actual layout produced will depend on whether the output image format can support it.") 
    90  .append (Argument ("spec", "specifier", "the data layout specifier.").type_string()), 
    91 
    92 Option ("prs", "DW gradient specified as PRS", "assume that the DW gradients are specified in the PRS frame (Siemens DICOM only)."), 
    93 
    94 Option::End 
    95 }; 
    96 
    97 
    98 
    99 inline bool next (Image::Position& ref, Image::Position& other, const std::vector<int>* pos) 
100 { 
101 int axis = 0; 
102 do { 
103  ref.inc (axis); 
104  if (ref[axis] < ref.dim(axis)) { 
105  other.set (axis, pos[axis][ref[axis]]); 
106  return (true); 
107  } 
108  ref.set (axis, 0); 
109  other.set (axis, pos[axis][0]); 
110  axis++; 
111 } while (axis < ref.ndim()); 
112 return (false); 
113 } 
114 
115 
116 
117 
118 
119 EXECUTE { 
120 std::vector<OptBase> opt = get_options (1); // vox 
121 std::vector<float> vox; 
122 if (opt.size()) 
123  vox = parse_floats (opt[0][0].get_string()); 
124 
125 
126 opt = get_options (3); // scale 
127 float scale = 1.0; 
128 if (opt.size()) scale = opt[0][0].get_float(); 
129 
130 opt = get_options (4); // offset 
131 float offset = 0.0; 
132 if (opt.size()) offset = opt[0][0].get_float(); 
133 
134 opt = get_options (5); // zero 
135 bool replace_NaN = opt.size(); 
136 
137 opt = get_options (6); // output 
138 Image::OutputType output_type = Image::Default; 
139 if (opt.size()) { 
140  switch (opt[0][0].get_int()) { 
141  case 0: output_type = Image::Real; break; 
142  case 1: output_type = Image::Imaginary; break; 
143  case 2: output_type = Image::Magnitude; break; 
144  case 3: output_type = Image::Phase; break; 
145  case 4: output_type = Image::RealImag; break; 
146  } 
147 } 
148 
149 
150 
151 
152 Image::Object &in_obj (*argument[0].get_image()); 
153 
154 Image::Header header (in_obj); 
155 
156 if (output_type == 0) { 
157  if (in_obj.is_complex()) output_type = Image::RealImag; 
158  else output_type = Image::Default; 
159 } 
160 
161 if (output_type == Image::RealImag) header.data_type = DataType::CFloat32; 
162 else if (output_type == Image::Phase) header.data_type = DataType::Float32; 
163 else header.data_type.unset_flag (DataType::ComplexNumber); 
164 
165 
166 opt = get_options (2); // datatype 
167 if (opt.size()) header.data_type.parse (data_type_choices[opt[0][0].get_int()]); 
168 
169 for (guint n = 0; n < vox.size(); n++) 
170  if (isfinite (vox[n])) header.axes.vox[n] = vox[n]; 
171 
172 opt = get_options (7); // layout 
173 if (opt.size()) { 
174  std::vector<Image::Axis> ax = parse_axes_specifier (header.axes, opt[0][0].get_string()); 
175  if (ax.size() != (guint) header.axes.ndim()) 
176  throw Exception (String("specified layout \"") + opt[0][0].get_string() + "\" does not match image dimensions"); 
177 
178  for (guint i = 0; i < ax.size(); i++) { 
179  header.axes.axis[i] = ax[i].axis; 
180  header.axes.forward[i] = ax[i].forward; 
181  } 
182 } 
183 
184 
185 opt = get_options (8); // prs 
186 if (opt.size() && header.DW_scheme.rows() && header.DW_scheme.columns()) { 
187  for (guint row = 0; row < header.DW_scheme.rows(); row++) { 
188  double tmp = header.DW_scheme(row, 0); 
189  header.DW_scheme(row, 0) = header.DW_scheme(row, 1); 
190  header.DW_scheme(row, 1) = tmp; 
191  header.DW_scheme(row, 2) = -header.DW_scheme(row, 2); 
192  } 
193 } 
194 
195 std::vector<int> pos[in_obj.ndim()]; 
196 
197 opt = get_options (0); // coord 
198 for (guint n = 0; n < opt.size(); n++) { 
199  int axis = opt[n][0].get_int(); 
200  if (pos[axis].size()) throw Exception ("\"coord\" option specified twice for axis " + str (axis)); 
201  pos[axis] = parse_ints (opt[n][1].get_string(), header.dim(axis)-1); 
202  header.axes.dim[axis] = pos[axis].size(); 
203 } 
204 
205 for (int n = 0; n < in_obj.ndim(); n++) { 
206  if (pos[n].empty()) { 
207  pos[n].resize (in_obj.dim(n)); 
208  for (guint i = 0; i < pos[n].size(); i++) pos[n][i] = i; 
209  } 
210 } 
211 
212 
213 in_obj.apply_scaling (scale, offset); 
214 
215 
216 
217 
218 
219 
220 Image::Position in (in_obj); 
221 Image::Position out (*argument[1].get_image (header)); 
222 
223 for (int n = 0; n < in.ndim(); n++) in.set (n, pos[n][0]); 
224 
225 ProgressBar::init (out.voxel_count(), "copying data..."); 
226 
227 do { 
228 
229  float re, im = 0.0; 
230  in.get (output_type, re, im); 
231  if (replace_NaN) if (gsl_isnan (re)) re = 0.0; 
232  out.re (re); 
233 
234  if (output_type == Image::RealImag) { 
235  if (replace_NaN) if (gsl_isnan (im)) im = 0.0; 
236  out.im (im); 
237  } 
238 
239  ProgressBar::inc(); 
240 } while (next (out, in, pos)); 
241 
242 ProgressBar::done(); 
243 } 
+4

Ten kod najwyraźniej używa jakichś dziwnych * makr * osłów. Aby to zrozumieć, musielibyśmy zobaczyć również wszystkie nagłówki. Mimo to pytanie to prawdopodobnie lepiej pasuje do [recenzji kodu] (http://codereview.stackexchange.com/). – Angew

+0

Możesz uzyskać pewien wgląd, uruchamiając tylko etap wstępnego przetwarzania/rozszerzania makr. Na przykład w GNU GCC jest to 'g ++ -E': wtedy możesz zobaczyć, co faktycznie robi EXECUTE z kodem. –

+5

Mam ochotę rzucić ci uprowadzenie tylko po to, aby przejąć inicjatywę przejścia przez to z debuggerem, co stawia cię przed około 99% ludzi, którzy zadają tu pytania. – WhozCraig

Odpowiedz

3

Jak zauważył w komentarzach, EXECUTE wydaje się być makro, jasno wynika z kontekstu nagłówek funkcji (a może nieco więcej, na przykład niektóre zmienne globalne i funkcje), a więc część w nawiasach klamrowych jest ciało funkcji. Aby uzyskać definicję EXECUTE, musisz przejrzeć nagłówki.

Jednakże, jeśli można osiągnąć pewną część kodu podczas debugowania, można wstawić string lub char[] w tym punkcie, nadając jej stringified wersję EXECUTE, więc masz cokolwiek preprocesor wyemituje dla EXECUTEna które pozycja w kodzie.

#define STR(x) #x 
#define STRINGIFY(x) STR(x) 
char c[] = STRINGIFY(EXECUTE); 

dwa makra to znana sztuczka makro, która pozwala uzyskać zawartość dowolnego makra w postaci literału. Wypróbuj go i sprawdź tablicę znaków w debuggerze, aby uzyskać zawartość egzekucji.

My dzikie przypuszczenie tutaj: EXECUTE jest główną funkcją lub zamiennik, tym OPTIONS i ARGUMENTS opisać jakie argumenty program oczekuje i jakie opcje wiersza poleceń można przekazać do niej. Te makra i niektóre z używanych funkcji i zmiennych (get_options, argument) są częścią małej struktury, która powinna ułatwić korzystanie, ocenę i informacje o opcjach wiersza poleceń.

+0

Cześć Arne, dzięki za odpowiedź. Dostałem app.h, która ma definicję EXECUTE, http://pastebin.com/6ZnAKxDC. Ta definicja byłaby taka sama jak w STRINGIFY? –

+0

@JesseRJ Tak, jak widzisz, jest to tylko trochę więcej niż główna funkcja: definiuje klasę za pomocą metody execute, a główna funkcja, która tworzy instancję obiektu tej klasy, wywołuje funkcję execute i obsługuje wszystkie wyjątki. Ciało funkcji, o którym mówiłem, to implementacja metody execute. –

+0

Teraz widzę, co masz na myśli "int main (int argc, gchar * argv []) {\ try {\ Aplikacja MyApp (...)" Widzę definicję "MyApp" i "App", ale nie dla "aplikacji". Jestem pewien, że "App" i "app" są całkowicie niezależnymi klasami lub funkcjami, prawda? Będę musiał wytropić aplikację? –