C ++ указатель арифметическая странность - PullRequest
1 голос
/ 27 июля 2011

Я нашел свою ошибку (через несколько часов) и изолировал ее в следующей программе. Проблема в том, как вычисляется значение переменной pst2 при использовании указателей на структуру. При использовании указателей на char все работает нормально. Почему это так?
(Используется версия gcc / g ++: (Debian 4.4.5-8) 4.4.5)
(Для тех, кому интересно: я получаю доступ к файлу-буферу, содержащему группировки данных с регулярными смещениями.)

#include <iostream>
#include "testpa.h"

#pragma pack(push)
#pragma pack(1)
//---------------------------
struct st_one
{
    int i;
    char c;
};
//---------------------------
struct st_two
{
    long l;
    int i;
};
#pragma pack(pop)

//===========================
int main()
{
    int n=1024, np1=sizeof(st_one); //, np2=sizeof(st_two);
    st_one *pst1, *pst1a;
    st_two *pst2, *pst2a;
    char *pc1, *pc2, *pc1a, *pc2a, *pb;

    pb = new char[n];

    pst1 = (st_one*)(pb);
    pst2 = (st_two*)(pst1 + np1); //using pst1
    pc1 = (char*)(pb);
    pc2 = (char*)(pc1 + np1); //using pc1

    pst1a = (st_one*)(pb);
    pst2a = (st_two*)(pb + np1); //using pb
    pc1a = (char*)(pb);
    pc2a = (char*)(pb + np1); //using pb

    std::cout << "\npb = " << (long)pb;
    std::cout << "\n-----";
    std::cout << "\npst1 = " << (long)pst1 << "\tpst2 = " << (long)pst2;
    std::cout << "\npc1  = " << (long)pc1 << "\tpc2  = " << (long)pc2;
    std::cout << "\n-----";
    std::cout << "\npst1a = " << (long)pst1a << "\tpst2a = " << (long)pst2a;
    std::cout << "\npc1a  = " << (long)pc1a << "\tpc2a  = " << (long)pc2a;
    std::cout << "\n-----\n";

    return 0;
}

Выход:

pb = 19546128

pst1 = 19546128         pst2 = 19546153  <--- WRONG!
pc1  = 19546128         pc2  = 19546133

pst1a = 19546128        pst2a = 19546133
pc1a  = 19546128        pc2a  = 19546133

Ответы [ 5 ]

8 голосов
/ 27 июля 2011

Это выглядит хорошо для меня. Линия:

 (pst1 + np1)

добавляет np1 экземпляров st_one к тому, на что указывает pst1, что означает, что значение pst1 s увеличивается на np1 * sizeof (st_one) байт, что составляет 25 (sizeof = 5), что соответствует значениям вы вывели. Вместо вышесказанного, я думаю, вы хотели:

 (pst1 + 1)

Значение pc1 работает, потому что это указатель char, поэтому строка:

(pc1 + np1)

добавляет np1 * sizeof (char) байтов к pc1, что составляет 5 байтов.

При увеличении указателя указатель указывает на следующий элемент в памяти, а не на следующий байт.

3 голосов
/ 27 июля 2011

Не следует добавлять sizeof(x), потому что это делается автоматически. Когда вы увеличиваете указатель, например ++ p, адрес увеличивается на размер объекта, чтобы он указывал на следующий.

Добавление 1 к указателю аналогично ++ p. Добавление sizeof(x) масштабирует приращение дважды.

Ваши вычисления работают нормально для char, потому что sizeof (char) равен 1.

2 голосов
/ 27 июля 2011

Арифметика указателя в C и C ++ выполняется умноженной на sizeof указатель на тип указателя. Таким образом, int *abc = /* ... */; int *def = abc + 1 приводит к тому, что def имеет результат на int впереди abc, а не char.

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

(впрочем, как и ваше приведение между типами указателей. C ++ говорит, что реализация тоже определена)

2 голосов
/ 27 июля 2011

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

1 голос
/ 27 июля 2011

Похоже, вы все неправильно поняли.Например, чтобы получить pst2 из pst1, вы должны увеличить его на единицу, так как указатель pst1 имеет тип st_one *, поэтому вы должны написать так:

pst2 = (st_two*)(pst1 + 1);

.. но у вас есть:

pst2 = (st_two*)(pst1 + np1);

... где np1 - это sizeof из st_one, поэтому он пропустит столько st_one структур, сколькоструктура имеет байты ...

Чтение некоторых документов по арифметике указателей, например this .

...