Почему указатель статического члена равен нулю в разделе ELF? - PullRequest
1 голос
/ 10 мая 2019

Скомпилируйте следующий код и извлеките раздел .ippalgo , я заметил, что поле name равно нулю, тогда как другие поля в порядке, как и ожидалось.

$ g++ a.cpp
$ objdump -s -j .ippalgo a.out

a.out:     file format elf64-x86-64

Contents of section .ippalgo:
 601040 00000000 00000000 02000000 01000000  ................
        ^^^^^^^^^^^^^^^^^
$ ./a.out
sizeof(char*): 8, sizeof(int): 4
name: 0x400648
name: abcdef

Но после изменения строки 1. , используя строку "abcdef", я, кажется, получил правильный адрес.

$ objdump -s -j .ippalgo a.out

a.out:     file format elf64-x86-64

Contents of section .ippalgo:
 601040 08064000 00000000 02000000 01000000  ..@.............
        ^^^^^^^^^^^^^^^^^
$ ./a.out
sizeof(char*): 8, sizeof(int): 4
name: 0x400608
name: abcdef

В любом случае последний отпечаток на главном получил правильное сообщение abcdef. У меня вопрос, почему я получил нули в первом случае, и как это исправить, если это проблема?

#include <cstdio>

struct DataInfo {
    const char* name;
    int id;
    int type;
};

class Proxy {
public:
    const static char *name;
    const static int type;
    const static int id;
};

const char* Proxy::name = "abcdef";
const int   Proxy::id = 1;
const int   Proxy::type = 2;

__attribute__((used, section(".ippalgo")))
DataInfo ProxyInfo = {
    Proxy::name,  // 1. ok when set "abcdef" directly
    Proxy::type,
    Proxy::id
};

int main()
{
    printf("sizeof(char*): %lu, sizeof(int): %lu\n",
           sizeof(char*), sizeof(int));
    printf("name: %p\n", Proxy::name);
    printf("name: %s\n", ProxyInfo.name);
}

1 Ответ

3 голосов
/ 10 мая 2019

TL; DR Proxy::name не равно const.


Существует две фазы инициализации статических данных: постоянная (включая инициализацию с нуля) и динамическая инициализация.

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

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

В вашем случае тот факт, что Proxy::name не является const как Proxy::id и Proxy::type, вероятно, влияет на выбор компилятора.Это даже не константа времени компиляции.Возможно, компилятор мог бы доказать, что никакой другой код инициализации не пишет в Proxy::name, но это нетривиально, поскольку class Proxy имеет внешнюю связь.Таким образом, даже постоянное распространение и применение правила «как будто» проваливают вас здесь.

constexpr было бы еще лучше убедить компилятор использовать постоянную инициализацию.Но вам по крайней мере нужно объявить Proxy::name как const.

...