2009-10-26 38 views
28

Tôi đang phát triển một công cụ để kết xuất dữ liệu từ các biến. Tôi cần phải đổ tên biến và cũng là các giá trị.Cách lập trình để lấy tên biến trong C?

Giải pháp của tôi: Lưu trữ tên biến dưới dạng chuỗi và in "tên biến", theo sau là giá trị của nó.

Có cách nào có lập trình để biết tên biến không?

Trả lời

47

Bạn có thể thử một cái gì đó như thế này:

#define DUMP(varname) fprintf(stderr, "%s = %x", #varname, varname); 

tôi sử dụng để sử dụng this header tôi đã viết, khi tôi mới đến C, nó có thể chứa một số ý tưởng hữu ích. Ví dụ này sẽ cho phép bạn in một giá trị C và cung cấp sự xác định định dạng trong một (cũng như một số thông tin bổ sung):

#define TRACE(fmt, var) \ 
     (error_at_line(0, 0, __FILE__, __LINE__, "%s : " fmt, #var, var)) 

Nếu bạn đang sử dụng C++, bạn có thể sử dụng các loại giá trị thông qua và xuất nó một cách thích hợp. Tôi có thể cung cấp một ví dụ hấp dẫn hơn nhiều về cách "in khá" các giá trị biến nếu đây là trường hợp.

+0

Đó là một ý tưởng tốt để làm những việc từ bên trong chương trình. Tạo ra một chuỗi các hằng số chuỗi, điều đó chắc chắn. –

+0

Có lẽ bạn nên định nghĩa nó là 'DUMP (varname, format)' và sử dụng '"% s = "format" \ n "' trong 'fprintf', cho phép nó hoạt động trên nhiều kiểu:' DUMP (somestring, "% s") 'hoặc' DUMP (someint, "% d") '. – caf

+0

Đây là cách thông thường xung quanh bản chất không nội tại của c. Như bạn có thể tưởng tượng, nó có giới hạn và bẫy của nó, nhưng nó là về tốt như bạn có thể làm mà không xây dựng thông dịch viên nội tâm của riêng bạn. – dmckee

1

Nếu tệp thực thi của bạn được biên dịch với thông tin gỡ lỗi, bạn có thể nhận được thông tin này. Nếu không, bạn có thể không may mắn. Vì vậy, bạn đang xây dựng một trình gỡ lỗi? Tại sao? Gỡ lỗi hiện tại cho c rất trưởng thành. Tại sao không sử dụng các công cụ hiện có thay vì tái phát minh ra bánh xe?

+0

số ví dụ về thẩm vấn các chương trình gỡ rối khi chạy xin vui lòng? –

11

Trong C, tên biến tồn tại trong bước biên dịch (và bước liên kết, nếu biến là toàn cầu), nhưng không có sẵn khi chạy. Bạn phải chọn một giải pháp liên quan đến một chuỗi chữ cho biết tên biến.

1

Không có cách nào tốt để làm điều đó từ bên trong chương trình của bạn, tôi sợ (ngoài câu trả lời của Anacrolix). Tôi nghĩ rằng giải pháp đúng cho vấn đề của bạn là một kịch bản trình gỡ lỗi. Trong hầu hết các trình gỡ rối, thậm chí bạn có thể treo nó lên để chạy mỗi khi trình gỡ lỗi ngắt thực thi chương trình (breakpoint, bạn nhấn ^C, v.v.) và nhận được ảnh chụp nhanh trạng thái chương trình của bạn mỗi khi bạn tương tác với nó.

4

Nếu bạn cần làm điều này cho các biến tùy ý thì có thể bạn sẽ cần sử dụng API trình gỡ lỗi mà trình biên dịch hoặc nền tảng cung cấp (như DbgHelp trên Windows).

Trên một số hệ thống nhúng mà tôi đã làm việc, chúng tôi cần có khả năng hiển thị trên các giá trị của các biến quan trọng nhất định được biết trước và thực hiện tất cả những gì chúng ta cần là một bảng Tên/con trỏ đơn giản :

typedef 
struct vartab { 
    char const* name; 
    int * var; 
} vartab; 


vartab varTable[] = { 
    { "foo", &foo }, 
    { "bar", &bar } 
}; 

Sau đó, tôi chỉ sử dụng một thói quen nhỏ để tìm kiếm tên biến được đề cập và đặt tên và dữ liệu được trỏ tới. Nếu bạn cần kết xuất dữ liệu ngoài ints đơn giản, bạn có thể mở rộng cấu trúc để giữ một trình định dạng kiểu printf và thay đổi con trỏ thành void* và chuyển dữ liệu đó tới snprintf() hoặc một thứ gì đó để định dạng dữ liệu.

Đôi khi tôi cũng sẽ sử dụng macro giúp xây dựng bảng (có thể cũng khai báo biến). Nhưng thành thật mà nói, tôi nghĩ rằng điều đó thực sự làm cho nó phức tạp hơn để hiểu (đặc biệt là đối với một người mới tham gia dự án - họ thường có một chút "WTF") và không thực sự đơn giản hóa nhiều thứ.

6

Tôi thực sự có một số mã có thể làm những gì bạn muốn. Nó sử dụng bộ tiền xử lý để xâu chuỗi tên biến để cho phép bạn in nó ra. Nó đổ cả tên biến và giá trị (dựa trên kiểu) và bố trí bộ nhớ cho biến đó.Các chương trình sau đây cho thấy cách nó được thực hiện:

#include <stdio.h> 
#include <stdlib.h> 

static void dumpMem (unsigned char *p, unsigned int s) { 
    int i; 
    unsigned char c[0x10]; 
    printf (">>  "); 
    for (i = 0; i < 0x10; i++) printf (" +%x",i); 
    printf (" +"); 
    for (i = 0; i < 0x10; i++) printf ("%x",i); 
    printf ("\n"); 
    for (i = 0; i < ((s + 15) & 0xfff0); i++) { 
     if ((i % 0x10) == 0) { 
      if (i != 0) printf (" %*.*s\n", 0x10, 0x10, c); 
      printf (">> %04x ",i); 
     } 
     if (i < s) { 
      printf (" %02x", p[i]); 
      c[i & 0xf] = ((p[i] < 0x20) || (p[i] > 0x7e)) ? '.' : p[i]; 
     } else { 
      printf (" "); 
      c[i & 0xf] = ' '; 
     } 
    } 
    printf (" %*.*s\n", 0x10, 0x10, c); 
} 
#define DUMPINT(x) do{printf("%s: %d\n",#x,x);dumpMem((char*)(&x),sizeof(int));}while(0) 
#define DUMPSTR(x) do{printf("%s: %s\n",#x,x);dumpMem(x,strlen(x));}while(0) 
#define DUMPMEM(x,s) do{printf("%s:\n",#x);dumpMem((char*)(&x),s);}while(0) 

typedef struct { 
    char c; 
    int i; 
    char c2[6]; 
} tStruct; 

int main (void) { 
    int i = 42; 
    char *s = "Hello there, my name is Pax!"; 
    tStruct z; 
    z.c = 'a'; z.i = 42; strcpy (z.c2,"Hello"); 

    DUMPINT (i); 
    DUMPSTR (s); 
    DUMPMEM (z,sizeof(z)); 

    return 0; 
} 

này kết quả đầu ra:

i: 42 
>>  +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +fabcdef 
>> 0000 2a 00 00 00          *... 
s: Hello there, my name is Pax! 
>>  +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +fabcdef 
>> 0000 48 65 6c 6c 6f 20 74 68 65 72 65 2c 20 6d 79 20 Hello there, my 
>> 0010 6e 61 6d 65 20 69 73 20 50 61 78 21    name is Pax! 
z: 
>>  +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +fabcdef 
>> 0000 61 b6 16 61 2a 00 00 00 48 65 6c 6c 6f 00 0d 61 a..a*...Hello..a 

Và, nếu bạn đang băn khoăn về sự tỉnh táo của do {...} while (0) trong macro, đó là để cho phép nó để được đặt bất cứ nơi nào trong mã mà không cần phải lo lắng về việc liệu bạn có đủ niềng răng xung quanh nó hay không.

3

Mọi người thường muốn các chương trình tự xem nội dung (hoặc "phản ánh" trong thuật ngữ hiện tại). Nhưng hầu hết các ngôn ngữ lập trình cung cấp ít (ví dụ, Java) hoặc không (C) khả năng phản ánh trên tất cả các chi tiết của một chương trình (tên biến, tên hàm, kiểu, cấu trúc biểu thức, v.v.).

Có cách để làm điều này cho tất cả ngôn ngữ: bước bên ngoài ngôn ngữ và sử dụng công cụ được thiết kế để trích xuất thông tin đó từ ngôn ngữ. Một lớp công cụ có thể làm điều này được gọi là một hệ thống chuyển đổi chương trình.

Xem này SO câu trả lời cho một cuộc thảo luận về làm thế nào để "có được tên biến" và các giá trị in sử dụng một hệ thống chuyển đổi chương trình: Trace changes to variables automatically

0

Hãy thử điều này.

#define MACRO_VARIABLE_TO_STRING(Variable) ((void) Variable,#Variable) 

Mã (void) Biến là chuyển đổi không có giá trị là no-op khi đó có toán tử dấu phẩy và macro xâu chuỗi. Vì vậy, kết quả ròng là const char * có chứa tên biến với kiểm tra trình biên dịch là biến thực sự tồn tại.

Bây giờ bạn có tên biến và bạn có thể sử dụng printf() để in giá trị của nó. cách

3

ngắn:

#define GET_VARIABLE_NAME(Variable) (#Variable) 

kiểm tra:

#include <string> 
class MyClass {}; 


int main(int argc, char* argv[]) { 
    int foo = 0; 

    std::string var_name1 = GET_VARIABLE_NAME(foo); 
    char* var_name2 = GET_VARIABLE_NAME(foo); 
    char* var_name3 = GET_VARIABLE_NAME(MyClass); 


    return 0; 
} 
Các vấn đề liên quan