размер типа данных без использования sizeof

У меня есть тип данных, скажем X, и я хочу знать его размер без объявления переменной или указателя этого типа и, конечно же, без использования оператора sizeof.

Это возможно? Я подумал об использовании стандартных файлов заголовков, которые содержат размер и диапазон типов данных, но не работают с типом данных, определяемым пользователем.


person sud03r    schedule 02.08.2009    source источник
comment
Что вы имеете в виду, конечно, без использования sizeof? Почему конечно?   -  person John Kugelman    schedule 02.08.2009
comment
Я предполагаю, потому что это загадка для интервью, ответ на которую опровергнет суть вопроса.   -  person Tyler McHenry    schedule 02.08.2009
comment
Загадка - вы должны найти необычный и, возможно, абсурдный способ ее решения. Смотрите мой ответ.   -  person Stefano Borini    schedule 02.08.2009
comment
Последующий вопрос: я хочу включить файл заголовка, который я написал, без использования каких-либо директив препроцессора, конечно. Как я могу это сделать?   -  person John Kugelman    schedule 02.08.2009
comment
кот foo.h ›x.c; кот foo.c ›› x.c; gcc x.c   -  person Stefano Borini    schedule 02.08.2009
comment
@Джон. Я считаю, что можно выполнить статическое связывание самостоятельно, распределяя указатели функций и записывая объектный код в позиции памяти. Хотя я понятия не имею обо всех деталях, как это сделать.   -  person Dana the Sane    schedule 02.08.2009
comment
@John, я однажды сделал это с ужасным конвейером оболочки для курса колледжа, который требовал, чтобы задание передавалось одним файлом. цорт очень сильно недооценен :)   -  person bdonlan    schedule 05.08.2009
comment
Почему имеет значение, должен ли этот человек что-то использовать или нет? Вопрос в том, как это сделать без использования sizeof, и мы можем помочь ответить на него или нет. Какая разница, если это испортит вопрос на собеседовании? Вся суть этого веб-сайта в том, чтобы помочь другим, а не разбирать вопрос до тех пор, пока он не соответствует тому, что мы хотим.   -  person Mike B    schedule 05.08.2009
comment
Далее в этой серии: как получить адрес без использования амперсанда. Быть в курсе!   -  person wildplasser    schedule 05.06.2012
comment
@wildplasser, как мне это сделать? Получение адреса без амперсанда?   -  person noufal    schedule 28.05.2013


Ответы (20)


На мой взгляд, это укладывается в категорию «как добавить два целых числа без использования ++, + = или +?». Это пустая трата времени. Вы можете попытаться избежать монстров неопределенного поведения, сделав что-то подобное.

size_t size = (size_t)(1 + ((X*)0));

Обратите внимание, что я не объявляю переменную типа или указателя на X.

person CB Bailey    schedule 02.08.2009
comment
Это, конечно, не соответствует стандартам, но в любом случае будет работать в большинстве реализаций. - person nos; 02.08.2009
comment
@Stephano: возможно, это самая ужасная вещь, которую вы видели в своей жизни, но это также более или менее похоже на то, как обычно реализуется offsetof ... - person Steve Jessop; 02.08.2009
comment
Хотя 0 гарантированно означает нулевой указатель во всех реализациях, он не обязательно должен быть внутренне представлен адресом 0, и в этом случае это не удастся. В C-FAQ утверждается, что такие машины действительно существуют c-faq.com/null/machexamp.html, но с ними вы вряд ли столкнетесь. Между прочим, умный ответ. :) - person Tyler McHenry; 05.08.2009
comment
Хороший момент, мне интересно, есть ли машины, на которых (size_t)(1 + ((X*)0) - ((X*)0)) с большей вероятностью будет работать. Обратите внимание: я использую гарантированную группировку слева направо add-expression. - person CB Bailey; 05.08.2009
comment
@Charles Balley: этот вопрос задают в интервью Cisco. Это не пустая трата времени и не глупый вопрос. - person Registered User; 17.06.2011
comment
@CharlesBailey: Что, если X - это ссылка? Ваше решение даже не компилируется, поскольку указатель на ссылку не разрешен стандартом C ++. - person Nawaz; 04.07.2012
comment
Кто-нибудь может объяснить, как это size_t работает? это похоже на кастинг? - person noufal; 28.05.2013
comment
@noufal size_t - это просто целочисленный тип без знака. Идея здесь состоит в том, чтобы указатель типа для проверки указывал на 0, операция 1+ выполняется между указателями, поэтому результат 0 увеличивается на размер указанного типа. Наконец, вы вернулись к size_t. Вы также можете объявить массив из двух элементов и вычислить различия между двумя адресами, однако это подразумевает объявление, которого можно избежать с помощью приведенного выше преобразования. - person DarioP; 16.07.2014
comment
(X*)0 возвращает нулевой указатель. Арифметика с нулевым указателем имеет неопределенное поведение. - person Keith Thompson; 22.02.2017
comment
@Nawaz: Привет из будущего! Вопрос помечен тегом C, поэтому мы можем с уверенностью предположить, что X не является ссылкой. - person Keith Thompson; 22.02.2017
comment
@KeithThompson: Ой ... да! ((Я сохраняю свой комментарий, чтобы другие не задавали тот же вопрос или не применяли ту же технику непосредственно в C ++, поскольку система типов C ++ немного сложнее)) - person Nawaz; 22.02.2017
comment
@KeithThompson: Арифметика с нулевым указателем имеет неопределенное поведение.. Действительно? Это арифметика или разыменование, что является неопределенным поведением? - person Nawaz; 22.02.2017
comment
@Nawaz: И то, и другое. Это разные операции, и оба имеют неопределенное поведение. - person Keith Thompson; 22.02.2017
comment
@KeithThompson: Я считаю, что в арифметику с нулевым указателем есть UB трудно поверить, если я не увижу цитату из спецификации. - person Nawaz; 22.02.2017
comment
@Nawaz: N1570 6.5.6, Аддитивные операторы: если и операнд-указатель, и результат указывают на элементы одного и того же объекта массива или на один за последним элементом объекта массива, оценка не должна приводить к переполнению; в противном случае поведение не определено. (Какого результата вы ожидали бы (int*)NULL + 1?) - person Keith Thompson; 22.02.2017
comment
@KeithThompson: Спасибо за цитату. Это полезно. - person Nawaz; 22.02.2017

Послушайте, sizeof - языковое средство для этого. Единственный, так что это единственный переносимый способ добиться этого.

В некоторых особых случаях вы можете сгенерировать непереносимый код, который использует другую эвристику для понимания размера конкретных объектов [*] (возможно, заставляя их отслеживать свой собственный размер), но вам придется выполнять всю бухгалтерию самостоятельно .

[*] Объекты в очень общем смысле, а не в смысле ООП.

person dmckee --- ex-moderator kitten    schedule 02.08.2009

Что ж, я любитель ... но я попробовал эту проблему и получил правильный ответ, не используя sizeof. Надеюсь, это поможет ... Я пытаюсь найти размер целого числа.

int *a,*s, v=10;

a=&v;

s=a;

a++;

int intsize=(int)a-(int)s;

printf("%d",intsize);
person bubblegum    schedule 05.08.2009
comment
Но заданный вопрос об этом без объявления переменной или указателя на переменную рассматриваемого типа .... - person ad absurdum; 10.09.2018

Правильный ответ на этот вопрос собеседования: «Зачем мне это нужно, если sizeof () делает это за меня и является единственным переносимым методом для этого?»

person Chris K    schedule 05.08.2009

Возможность заполнения препятствует всем надеждам без знания правил, используемых для его введения. И это зависит от реализации.

person AProgrammer    schedule 02.08.2009

Вы можете разгадать это, прочитав , в котором размещены структуры вашей памяти ABI, nofollow, nofollow в вашем процессоре. Это потенциально разное для каждого процессора. Но если вы не пишете компилятор, удивительно, что вы не хотите просто использовать sizeof, что является единственно правильным способом решения этой проблемы.

person Norman Ramsey    schedule 02.08.2009

если X - тип данных:

#define SIZEOF(X) (unsigned int)( (X *)0+1 )

если X - переменная:

#define SIZEOF(X) (unsigned int)( (char *)(&X+1)-(char *)(&X) )
person Community    schedule 11.02.2011

Попробуй это:

int a;
printf("%u\n", (int)(&a+1)-(int)(&a));
person Majid    schedule 15.11.2009
comment
Я пробовал этот метод, но получаю предупреждение .. warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] ... Хотелось бы избавиться от этого? - person noufal; 28.05.2013

Загляните в исходники компилятора. Ты получишь :

  • размер стандартных типов данных.
  • правила заполнения структур

и отсюда ожидаемый размер чего угодно.

Если бы вы могли хотя бы выделить место для переменной и ввести в нее какое-то контрольное значение, вы могли бы изменить его бит за битом и посмотреть, изменится ли значение, но это все равно не сообщит вам никакой информации о заполнении.

person Stefano Borini    schedule 02.08.2009
comment
Компилятор всегда может добавлять дополнительные отступы где угодно, поэтому «ожидаемого размера» нет, за исключением sizeof (char), который определен как 1. Обратите внимание, что char может иметь более 8 бит, однако ... - person bdonlan; 05.08.2009
comment
Неужели в C может быть больше 8 бит? В C ++ он определяется как ровно 1 байт (логический вывод: sizeof () возвращает размер аргумента в байтах, sizeof (char) == 1 = ›char - ровно один байт) - person David Rodríguez - dribeas; 09.09.2009
comment
Слово байт не всегда означает 8 бит. Это в основном определяется как наименьшая индивидуально адресуемая единица памяти. На сегодняшний день наиболее распространены 8-битные байты, но могут быть (и были!) Системы с 9-битными и даже 36-битными байтами, и возможна система с 32-битными байтами, если это еще не сделано. существует. - person cHao; 17.06.2011

Попробуй это:

 #include<stdio.h>

int main(){

  int *ptr = 0;

  ptr++;
  printf("Size of int:  %d",ptr);

  return 0;
person Sateesh    schedule 06.07.2013

Доступно с версии C89, которая в пользовательском коде:

  1. Не объявляет переменную типа X.
  2. Не объявляет указатель на тип X.
  3. Без использования оператора sizeof.

Достаточно просто сделать, используя стандартный код, как подсказал @steve jessop

offsetof(type, member-designator)

которое расширяется до целочисленного константного выражения типа size_t, значение которого представляет собой смещение в байтах, до элемента структуры ..., от начала его структуры ... C11 §7.19 3

#include <stddef.h>
#include <stdio.h>

typedef struct {
  X member;
  unsigned char uc;
} sud03r_type;

int main() {
  printf("Size X: %zu\n", offsetof(sud03r_type, uc));
  return 0;
}

Примечание. В этом коде используется "%zu", для которого требуется C99 и далее.

person chux - Reinstate Monica    schedule 22.02.2017
comment
Между элементами может быть отступ. - person 2501; 22.02.2017
comment
@ 2501 Возможно, заполнение. Возможна обивка. Я ожидал, что это будет редкостью для unsigned char. - person chux - Reinstate Monica; 22.02.2017

Это код: уловка состоит в том, чтобы создать объект-указатель, сохранить его адрес, увеличить указатель и затем вычесть новый адрес из предыдущего. Ключевым моментом является то, что когда указатель увеличивается, он фактически перемещается на размер, равный объекту, на который он указывает, поэтому здесь размер класса (из которого объект, на который он указывает).

#include<iostream>
using namespace std;
 class abc
    {
           int a[5];
           float c;           
    };
main()
{
    abc* obj1;
    long int s1;
    s1=(int)obj1; 
    obj1++;
    long int s2=(int)obj1;
    printf("%d",s2-s1);
}

С Уважением

person swati kunte    schedule 07.10.2012

Многие из этих ответов предполагают, что вы знаете, как будет выглядеть ваша структура. Я считаю, что этот вопрос на собеседовании призван побудить вас мыслить нестандартно. Я искал ответ, но не нашел здесь подходящих решений. Я сделаю лучшее предположение, сказав

struct foo {
  int a;
  banana b;
  char c;
  ...
};

Создав foo [2], я теперь буду иметь в памяти 2 последовательных объекта foo. Так...

foo[2] buffer = new foo[2];
foo a = buffer[0];
foo b = buffer[1];

return (&b-&a);

Предполагая, что мои арифметические операции с указателем были выполнены правильно, это должен быть билет - и его переносимый! К сожалению, такие вещи, как отступы, настройки компилятора и т. Д., Тоже сыграли свою роль.

Мысли?

person mohbandy    schedule 09.03.2013

поместите это в свой код

затем проверьте вывод компоновщика (файл карты)

unsigned int  uint_nabil;
unsigned long  ulong_nabil;

у вас получится что-то вроде этого;

uint_nabil 700089a8 00000004
ulong_nabil 700089ac    00000004

4 это размер !!

person Smartfusion    schedule 24.06.2017

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

#include <iostream>
using namespace std;

int main()
{
    int arr[2];
    int* ptr = &arr[0];
    int* ptr1 = &arr[1];
    cout <<(size_t)ptr1-(size_t)ptr;
}

Надеюсь это поможет.

person Rohan Shahane    schedule 03.10.2017

Попробуй это,

#define sizeof_type( type )  ((size_t)((type*)1000 + 1 )-(size_t)((type*)1000))

Для следующего определяемого пользователем типа данных

struct x
{
    char c;
    int i;
};

sizeof_type(x)          = 8
(size_t)((x*)1000 + 1 ) = 1008
(size_t)((x*)1000)      = 1000
person josh    schedule 12.11.2010
comment
(x*)0 - это определенное поведение, (x*)1000 - неопределенное поведение. - person kay; 06.06.2012

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

#include <iostream>
int main () {
    unsigned int i = 1;
    unsigned int int_bits = 0;
    while (i!=0) {
        i <<= 1;
        ++int_bits;
    }

    unsigned char uc = 1;
    unsigned int char_bits = 0;
    while (uc!=0) {
        uc <<= 1;
        ++char_bits;
    }

    std::cout << "Type int has " << int_bits << "bits.\n";
    std::cout << "This would be  " << int_bits/8 << " IT bytes and "
              << int_bits/char_bits << " C++ bytes on your platform.\n";
    std::cout << "Anyways, not all bits might be usable by you. Hah.\n";
}

Конечно, вы могли бы просто #include <limit> или <climits>.

person Sebastian Mach    schedule 17.06.2011

    main()    
    {
    clrscr();
    int n;
    float x,*a,*b;//line 1
    a=&x;
    b=(a+1);
    printf("size of x is %d",
    n=(char*)(b)-(char*)a);
    }

С помощью этого скрипта кода размер любых данных может быть вычислен без оператора sizeof. Просто измените значение с плавающей запятой в строке 1 на тип, размер которого вы хотите вычислить.

person Yash Tyagi    schedule 29.03.2015

person    schedule
comment
При добавлении нескольких ответов на вопрос, пожалуйста, включите к ним объяснение, объясняющее разницу. - person Matt; 23.02.2017

person    schedule
comment
Возникает вопрос, как это сделать, не объявляя переменную или указатель этого типа .... - person ad absurdum; 10.09.2018
comment
Есть несколько проблем с этим ответом. Он использует указатель, который недействителен в соответствии с вопросом. Это C ++, хотя есть только тег языка C, и он также вызывает неопределенное поведение при печати указателя с описателем формата "%d". - person Gerhardh; 10.09.2018