искаженное имя на C

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

https://gustedt.wordpress.com/2011/06/24/name-mangling-in-c/

Вопрос здесь в том, если в любом случае этот компилятор исказит имя функции C?


person user454083    schedule 06.06.2015    source источник
comment
Ответ на ваш вопрос содержится в блоге, на который вы ссылаетесь; так что ты не понимаешь?   -  person Clifford    schedule 06.06.2015
comment
@ChronoKitsune Вероятно, это должен быть ответ.   -  person Sinkingpoint    schedule 06.06.2015


Ответы (2)


Поскольку C — это язык программирования, который не поддерживает перегрузку функций имен, он не искажает имена. Но для компиляторов, ориентированных на платформу Microsoft Windows, которая имеет множество соглашений о вызовах, таких как _cdecl, _stdcall и т. д., имена функций искажены, чтобы предоставить информацию о соглашении о вызовах.

Например,

 int _stdcall fun(int myVar) {return 0;}
 int _fastcall fun(int myVar){return 1;}
 int _cdecl fun(int myVar){return 2;}

вывод компилятора (32-битный) будет таким:

 _fun@4  /* _(function_name)@(argument_size_in_bytes) */
 @fun@4 /* @(function_name)@(argument_size_in_bytes) */
 _fun /* _(function_name) */
person Tech Trivia    schedule 19.04.2020

Имена функций не будут искажены, за исключением, по-видимому, идентификаторов Unicode. Например:

// Mangled as "o_u03ba" using Intel's compiler "icc").
extern int o\u03ba(void);

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

//Both will have the same symbol name.
extern void o\u03ba(volatile int *p)
{
    *p = -32767;
}

extern void o_u03ba(volatile int *p)
{
    *p = 0;
}

...

volatile int n;

// Should print -32767; may print 0 or -32767.
o\u03ba(&n);
printf("%d\n", n);

// Should print 0; will print the same thing as the previous line.
o_u03ba(&n);
printf("%d\n", n);

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

static void foo\u03ba(volatile int n)
{
    printf("foo\\u03ba: n = %d\n", n);
}

static void foo_u03ba(volatile int n)
{
    printf("foo_u03ba: n = %d\n", n);
}

...

volatile int n = 10;

// These two lines may print the same thing.
foo\u03ba(n);
foo_u03ba(n);

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

person Community    schedule 06.06.2015
comment
То, что вы печатаете как приблизительный адрес функции, на самом деле является адресом стека. - person Dani; 06.06.2015
comment
@ Дани, я не думал, когда делал это. Отредактировано. - person ; 06.06.2015
comment
Я не уверен, что редактирование улучшило ситуацию. Теперь вы печатаете значение параметра, а не адрес параметра в стеке или адрес функции. На большинстве машин можно обойтись printf("%s: %p\n", __func__, (void *)foo\u03ba);, так как на большинстве машин размер указателя на функцию такой же, как размер указателя на объект. Однако это формально не гарантируется ни стандартом C (ни POSIX, за исключением того, что dlsym() должно работать для функций и возвращает void *). […продолжение…] - person Jonathan Leffler; 07.06.2015
comment
[…продолжение…] Вам нужно будет принять решение о том, в какой степени вы хотите получить теоретическую идеальную переносимость по сравнению с практической «работой на практике на машинах, которые мы используем в данный момент и можем предвидеть использование» переносимости. . - person Jonathan Leffler; 07.06.2015
comment
@JonathanLeffler Ясность исходит из тонкой разницы в выводе. foo\u03ba: 10 будет напечатано в случае вызова foo\u03ba, а foo_u03ba: 10 будет напечатано в случае вызова foo_u03ba. У gcc нет проблем с этим (вызываются обе функции), но у icc возникнет проблема (будет вызываться только одна функция из-за используемой схемы искажения). Тем не менее, я согласен с тем, что большинство компиляторов с радостью будут работать с такой конструкцией, как printf("%p\n", (void *)foo\u03ba);, и, следовательно, ваша точка зрения верна. - person ; 07.06.2015