У C, SizeOf аператар вяртае 8 байт пры перадачы, але 2,5 м 4 байта пры праходжанні 1.25m * 2

Я не разумею, чаму SizeOf Аператар вырабляе наступныя вынікі:

sizeof( 2500000000 )//=> 8 (8 bytes).

... яна вяртае 8, і калі я раблю наступнае:

sizeof( 1250000000 * 2 )//=> 4 (4 bytes).

... яна вяртае 4, а не 8 (што я спадзяваўся). Можа хто-то высветліць, як SizeOf вызначае памер экспрессионной (або тыпу дадзеных) і чаму ў маім канкрэтным выпадку гэта адбываецца?

Маё меркаваньне, што SizeOf аператар з'яўляецца аператарам часу кампіляцыі.

Bounty Question: Is there a run time operator that can evaluate these expressions and produce my expected output (without casting)?

65
@JacobPollack не, гэта не так. * 2 1,5-b не вызначана паводзіны падчас выканання.
дададзена аўтар Luchian Grigore, крыніца
@RogerRowland на самай справе гэта звычайная практыка, і рэкамендуецца ўжываць SizeOf для рэальных аб'ектаў, а не класаў.
дададзена аўтар Luchian Grigore, крыніца
@RogerRowland што вы маеце на ўвазе SIZEOF ня литералов?
дададзена аўтар Luchian Grigore, крыніца
@JacobPollack: Наколькі я ведаю, вы не можаце даць ўзнагароду таму, хто не размясціў адказ.
дададзена аўтар Keith Thompson, крыніца
Ключавым момантам з'яўляецца тое, што (у большасці выпадкаў) выразы C ацэньваюцца незалежна ад кантэксту, у якім яны з'яўляюцца. Тып 1250000000 адно і тое ж, незалежна ад таго, з'яўляецца яна часткай 1250000000 * 2 ці не.
дададзена аўтар Keith Thompson, крыніца
@JacobPollack: для зменнай даўжыні масіваў Акрамя гэтага, памер кожнага выразы вызначаецца падчас кампіляцыі. Я думаю, што вы пытаецеся ёсць, напрыклад, пры Int х = Foo; ИНТ у = бар; , як вялікі цэлалікавых тып (ці якой цэлалікавых тып) вам трэба захаваць вынік множання х па у без пераліву. Там няма простага спосабу зрабіць да гэтага; З даволі шмат лісця, якія да вас.
дададзена аўтар Keith Thompson, крыніца
<�Код> SizeOf можа быць выкарыстаны на тыпе або выразы. Литералы з'яўляюцца выразамі; яны выдатныя.
дададзена аўтар Jonathan Leffler, крыніца
@RogerRowland: памер size_t = SizeOf (some_array)/SizeOf (some_array [0]) пераважней памер size_t = SizeOf (some_array)/SizeOf (array_type) , таму што, калі тып змяненняў масіва, ваш код не раптоўна зламаўся. Дык не, SizeOf не «для тыпаў, ня литералы».
дададзена аўтар Ed S., крыніца
@JacobPollack Калі вы хочаце ведаць, калі цэлае множанне A * B перапаўняецца, вы можаце праверыць, калі INT_MAX/а> Ь; але сцеражыцеся дэталяў падпісанай дзялення нацэлілася і пагранічных выпадкаў. Гэта складана зрабіць гэта надзейна і пераноснасць для ўсіх значэнняў а і Ь.
дададзена аўтар Jens, крыніца
дададзена аўтар Jonathon Reinhart, крыніца
Акрамя таго, вельмі падобны на stackoverflow.com/questions/ 5537276/чамусьці sizeof13-33-гэта-8-бэт & ZWNJ; ES , акрамя як з цэлымі лікамі, а не паплаўкамі.
дададзена аўтар Matt B., крыніца
@JacobPollack: «аўтарытэтны даведнік» з'яўляецца раздзел 6.5.3.4.2, «Элемент SizeOf Аператар дае памер (у байтах) свайго аперанда, які можа быць выраз у дужках або імя тыпу ». У вашым другім выпадку аперанд з'яўляецца выразам тыпу Int , Int займае 4 байта на вашай сістэме, таму яна дае 4 . Там не здаецца, што-то тут складаней. Тып будзе Int «падчас выканання», таксама.
дададзена аўтар Paul Griffiths, крыніца
калі вы не зацікаўленыя ў C ++ і арыентаваны на C, калі ласка, выдаліце ​​C ++ тэг
дададзена аўтар UpAndAdam, крыніца
<�Код> SizeOf для тыпаў, а не литералы, і ацэньваюцца падчас кампіляцыі - чаму вы павінны гэта зрабіць?
дададзена аўтар Roger Rowland, крыніца
@LuchianGrigore - я маю на ўвазе, звычайна ён выкарыстоўваецца для вызначэння памеру некаторага структура або масіў, проста цікава, калі OP блытае яго са знаходжаннем колькасці бітаў у міжнар, напрыклад.
дададзена аўтар Roger Rowland, крыніца
Ёсць у любым выпадку, каб вызначыць, памяць, выдзеленую на час выканання? Я хачу бачыць, што * 2 1,5-b ўяўляе сабой 8 байт тыпу дадзеных (г.зн. доўга) падчас выканання.
дададзена аўтар Jacob Pollack, крыніца
Я абнавіў арыгінальны пост, каб быць больш яснымі і больш кароткім да праблемы, усталяванай для будучых гледачоў.
дададзена аўтар Jacob Pollack, крыніца
@KeithThompson, ці ёсць спосаб, каб вызначыць памер ацэньваецца выразы падчас выканання? Ці ёсць спосаб, каб паставіць яго ў нейкім «бязмежнай» часовай памяці, каб убачыць колькасць байт, неабходных для захоўвання выніку некаторых арыфметычнай аперацыі. Тое, што я прасіў, хутчэй за ўсё, не тэхнічна правільна, але робіць гэта функцыя, як, што існуюць у C99?
дададзена аўтар Jacob Pollack, крыніца
@PaulGriffiths (+1) Я разумею, што цяпер (з адказаў ніжэй, а) - прычына, я адкрыў Баунті мой наступны пытанне. Я зраблю гэта больш ясна ў маёй пасады (рэдагаванне у цяперашні час).
дададзена аўтар Jacob Pollack, крыніца
@PaulGriffiths, я зраблю новае пытанне, як вы прапанавалі. Я не хацеў рызыкаваць быць пазначаны як дублікат, таму я зрабіў шчадроты, каб убачыць, калі хто-то гатовыя змяніць існуючы адказ ўключыць, што наступныя меры.
дададзена аўтар Jacob Pollack, крыніца
@KeithThompson, мае сэнс цяпер, дзякуй за гэта. Апублікаваць яго ў якасці наступных мер, і я дам вам шчодрасць (але прыняты адказ застаецца з Luchian).
дададзена аўтар Jacob Pollack, крыніца
@KeithThompson, пра парадак. Ну дзякуй не менш за тлумачэнне. Я прысудзіць ўзнагароду ў 23 гадзін на іншы адказ, калі ён перагледжаны (як я павінен чакаць, пакуль не будуць занесеныя змены).
дададзена аўтар Jacob Pollack, крыніца

8 адказы

2500000000 doesn't fit in an int, so the compiler correctly interprets it as a long (or long long, or a type where it fits). 1250000000 does, and so does 2. The parameter to sizeof isn't evaluated, so the compiler can't possibly know that the multiplication doesn't fit in an int, and so returns the size of an int.

Акрамя таго, нават калі параметр быў ацэнены, вы, верагодна, атрымаеце перапаўненне (і нявызначаны паводзіны), але, верагодна, да гэтага часу прыводзіць да 4 .

тут:

#include 
int main()
{
    long long x = 1250000000 * 2;
    std::cout << x;
}

Вы можаце выказаць здагадку выхад? Калі вы думаеце, што 2500000000 , вы памыляецеся. Тып выказвання 1250000000 * 2 гэта Int , паколькі аперанды Int і Int і множанне ISN » т автомагіческі павышаны да большага тыпу дадзеных, калі ён не падыходзіць.

http://ideone.com/4Adf97

Дык вось, НКУ кажа, што -1794967296 , але гэта нявызначаны паводзіны, так што можа быць любую колькасць. Гэты лік не ўпісваецца ў Int .

Акрамя таго, калі вы накладваеце адзін з аперанд чаканага тыпу (гэтак жа, як вы прыводзіце цэлыя лікі, калі дзеляцца, калі вы шукаеце нецелых вынік), вы ўбачыце гэтую працу:

#include 
int main()
{
    long long x = (long long)1250000000 * 2;
    std::cout << x;
}

дае правільны 2500000000 .

123
дададзена
Або 1250000000LL * 2
дададзена аўтар 0x499602D2, крыніца
@LuchianGrigore я не разумею, як SizeOf з выражение2 4? [Новы карыстальнік]
дададзена аўтар Dineshkumar, крыніца
@RogerRowland самае галоўнае, стандарт кажа аперанд SizeOf Не ацэньваецца.
дададзена аўтар Luchian Grigore, крыніца
@Dineshkumar тыпу Выраз з'яўляецца Int нават калi сапраўдны вынік выразы не ўкладаецца ў адзін.
дададзена аўтар Luchian Grigore, крыніца
@JacobPollack аб'ём памяці, адно і тое ж (4), нават калі яна пераліваецца. Калі вы чакаеце, што перапаўненне, выкарыстоўвайце доўгі доўгі , каб пачаць з. Ці вялікі клас нумар.
дададзена аўтар Luchian Grigore, крыніца
@xaxxon як бы ўнутранае прадстаўленне дапаможа вызначыць памер выніку выразы, якое прыводзіць да нявызначанаму паводзінам?
дададзена аўтар Luchian Grigore, крыніца
@Oberon ха я бачу, што вы там рабілі!
дададзена аўтар Luchian Grigore, крыніца
@LuchianGrigore, ён толькі са спасылкай на што цалкам дамінуючы спосаб прадстаўлення цэлых лікаў сёння з'яўляецца з 2s камлементу, і таму адтуль вы можаце ведаць, як вялікія ліку а uint32_t можа прадстаўляць. (Напрыклад.)
дададзена аўтар Prof. Falken, крыніца
Замест ліцця, лепш дадаць LL суфікс.
дададзена аўтар Oberon, крыніца
Так, для VC ++, MSDN кажа, што выраз ня вылічаецца - msdn.microsoft.com/en-us/library/4s7x1k91 (v = vs.71) .aspx
дададзена аўтар Roger Rowland, крыніца
@JacobPollack: Ад стандарту C11, раздзел 6.5.3.4, SizeOf : «Калі тыпу аперанда з'яўляецца зменнай даўжынёй тыпу масіва, аперанд вылічаецца, у адваротным выпадку, аперанд не вылічваецца і вынік з'яўляецца цэлай канстантай «.
дададзена аўтар bta, крыніца
Вы можаце даведацца, які памер неабходны для захоўвання любой Int, калі вы ведаеце, ўнутранае прадстаўленне (амаль заўсёды 2s камлементу), таму выкарыстаць размерный Int як u_int32 або u_int64. Няма неабходнасці, каб папрасіць кампілятар.
дададзена аўтар xaxxon, крыніца
сказаў @LuchianGrigore Што Prof Falken. Вам не патрэбныя SizeOf() на ўсе, каб вызначыць, які тып выкарыстоўваць для прадстаўлення вызначанага ліку, вы можаце проста высветліць гэта загадзя для сябе з некаторай асноўны бінарнай матэматыкай.
дададзена аўтар xaxxon, крыніца
Я шукаю каго-небудзь, каб працытаваць стандарт C99 для мяне. Гэта па-ранейшаму фантастычны адказ, хоць і, калі ніхто не робіць я зноў прыняць гэта. Калі б можна было спаслацца на стандарт C99 таксама тады я дам вам шчодрасцю і паўторна прыняць яго.
дададзена аўтар Jacob Pollack, крыніца
@LuchianGrigore Добра дзякуй чалавеку.
дададзена аўтар Jacob Pollack, крыніца
Так, так я разумею, што SizeOf ацэньваецца падчас кампіляцыі. Ёсць у любым выпадку, каб вызначыць аб'ём памяці, дадзенае выраз на час выканання?
дададзена аўтар Jacob Pollack, крыніца

[Edit: я не заўважыў, на пачатковым этапе, што гэта была апублікавана і як C і C ++. Я адказваю толькі ў адносінах да С.]

Адказваючы на ​​ваша пытанне Наступныя, «Ці ёсць у любым выпадку, каб вызначыць аб'ём памяці, выдзеленай для выражэння або зменнай падчас выканання?»: Ну, не зусім. Праблема заключаецца ў тым, што гэта не вельмі добра сфармаваўся пытанне.

«Выразы», ​​у C-на-мове (у адрозненне ад канкрэтнай рэалізацыі), на самай справе не выкарыстоўваць любы памяці. (Канкрэтныя рэалізацыі трэба некаторы код і/або памяці дадзеных для захоўвання вылічэнняў, у залежнасці ад таго, колькі вынікаў будзе ўпісвацца ў рэгістры працэсара і гэтак далей.) Калі вынік выразы ня прыхавана ў зменнай, яна проста знікае (і кампілятар можа часта апускаем падчас выканання кода, каб вылічыць ніколі не захаваны вынік). Мова не дае вам спосаб, каб спытаць пра што-то не прымае на сябе існуе, гэта значыць, прастора для захоўвання выразаў.

Зменныя, з другога боку, не займаюць памяць (памяць). Дэкларацыя пераменнага паведамляе кампілятар, колькі дыскавай прасторы для ўстаноўкі ў баку. для масівы зменнай даўжыні C99, за выключэннем, аднак, захоўванне патрабуецца вызначаецца выключна ў кампіляцыі час, а не падчас выканання. Менавіта таму SizeOf х як правіла, з'яўляецца пастаянным выразам: кампілятар можа (і на самай справе неабходна) вызначыць значэнне SIZEOF х падчас кампіляцыі.

Улас C99 з'яўляецца спецыяльным выключэннем з гэтага правіла:

void f(int n) {
    char buf[n];
    ...
}

Захоўвання патрабуецца для Buf не з'яўляецца (у агульным) то кампілятар можа знайсці падчас кампіляцыі, таму SizeOf ЬиЕ не з'яўляецца канстантай падчас кампіляцыі. У гэтым выпадку, ЬиЕ фактычна вылучаецца падчас выканання і яго памер вызначаецца толькі тады. Так SizeOf ЬиЕ з'яўляецца выраз выканання вылічанага.

У большасці выпадкаў, аднак, усе памеры фронт, падчас кампіляцыі, і калі выраз перацякае падчас выканання, паводзіны не вызначана, вызначаецца рэалізацыяй, ці добра вызначаецца ў залежнасці ад тыпу. Цэлы лік ад перапаўнення, як у 2,5 млрд, памножанай на 2, калі INT_MAX толькі крыху больш за 2,7 мільярда даляраў, прыводзіць да «нявызначаны паводзіны». Беззнаковых цэлых робяць модульную арыфметыку і, такім чынам, дазваляе разлічыць у GF (2 да ).

Калі вы хочаце, каб пераканацца, што некаторыя вылічэнні не могуць перапоўніцца, што тое, што вы павінны вылічыць самастойна, падчас выканання. Гэта вялікая частка таго, што робіць multiprecision бібліятэкі (як ПНП) цяжка напісаць у C-гэта, як правіла, нашмат прасцей, а таксама хутчэй, каб кадзіраваць вялікія часткі, што ў зборцы і скарыстацца вядомымі ўласцівасцямі працэсара (напрыклад, перапаўненне сцягі, ці падвойная шырыня выніку-рэгістр-пар).

8
дададзена
Цікава, не ведаў, C99 SizeOf ацэньвае масіваў падчас выканання. +1
дададзена аўтар Luchian Grigore, крыніца
@xaxxon: правільна, толькі Улас вынік часу выканання работы SIZEOF .
дададзена аўтар torek, крыніца
не ўсе масівы, я не веру, толькі тыя, дзе ён не можа вызначыць памер падчас кампіляцыі - дзе ён мае зменную даўжыню.
дададзена аўтар xaxxon, крыніца

Luchian адказаў ўжо. Толькі для поўнага яго ..

С11 Стандартных стану (стандарт C ++ мае аналагічныя лініі), што тып цэлага ліку без якога-небудзь літаральнага суфікса, які пазначае тыпу з'яўляецца dertermined наступным чынам:

From 6.4.4 Constants (C11 draft):

<�Р> Семантыка </р>      <�Р> 4 Значэнні дзесятковай канстанты роўна вылічанае падставу 10; што з   васьмярковы канстанта, падстава 8; што з шаснаццатковай канстанты, падстава 16.   лексічны першая лічба з'яўляецца найбольш значнай.      <�Р> <�моцны> 5 Тып цэлалікавай канстанты з'яўляецца першым з адпаведнага    спіс, у якім яго значэнне можа быць прадстаўлена. </моцны> </р>

І табліца выглядае наступным чынам:

дзесятковая канстанта

int
int long int 
long long int

Octal or Hexaдзесятковая канстанта

int
unsigned int
long int
unsigned long int
long long int
unsigned long long int

For Octal and Hexaдзесятковая канстантаs, even unsigned types are possible. So depending on your platform whichever in the above list (int or long int or long long int) fits first (in the order) will be the type of integer literal.

6
дададзена
Акрамя Уласаў, кампілятар мае інфармацыю аб памеры для тыпаў. Такім чынам, можна вызначыць, ці з'яўляецца цэлы лік літаральнага будзе ўпісвацца ў ў адным з тыпаў available.As Торек сказаў у сваім адказе, кампілятар павінен ацаніць аперанд SizeOf ў выпадку C99 Уласаў. (Дарэчы, Vlas зроблены неабавязковымі ў с11). Але кампіляваць ацэнкі часу памеру больш прамой, чым гэта.
дададзена аўтар P.P., крыніца
Я не ведаю, як гэта дакладна кампілятар вылічае тып. Напрыклад, GCC выдае wanring для SizeOf (9999999999999999999): папярэджанне: цэлалікавых канстанта занадта вялікая для доўгага тыпу . Я не ведаю дакладна працуе складальніка, як ён вызначае памер для литералов. Але ён правярае: 1. Ці з'яўляецца литерал мае любы суфікс, які пазначае тып. Калі так, то выкарыстаць гэты тып, каб адпавядаць. Напрыклад, SizeOf (1L) будзе SizeOf (доўгі) нават калі літаральнае 1 будзе падыходзяць ў міжнар.
дададзена аўтар P.P., крыніца
2. Калі няма суфікса, то прытрымлівайцеся прыведзеных вышэй парадку, пачынаючы з міжнар знайсці памер. 3. Калі нічога не літаральнае занадта вялікая, каб адпавядаць любому з тыпаў, то выдае дыягнастычны.
дададзена аўтар P.P., крыніца
@PascalCuoq доўгі доўгі даступны, пачынаючы з С99. Так што я б ігнараваць compling з «GCC t.c» (які стандарт гэты код адпавядаюць?), Як правіла, GCC ўключае ў сябе мноства нестандартных пашырэнняў. C99 (і с11) патрабуе названага парадку, які будзе выкарыстоўвацца для якія вызначылі тыпаў литералов і «-0x80000000» могуць быць прадстаўлены ў Int <�код /> тыпу (INT_MIN толькі што ў маёй сістэме), яна павінна быць надрукаваная -2147483648. (Я прайграў тое ж самае з GCC 4.7.3). Гэта, вядома, па-відаць, выпадак НКУ, не задавальняюць патрабаванням С99 ст. [Працяг]
дададзена аўтар P.P., крыніца
Як ні дзіўна, аказваецца, праблема разглядаецца толькі з доўгі доўгі л; Напрыклад, калі я выкарыстоўваю Int л; або доўгі л; , I атрымаць правільную выснову (-2147483648). Так як -2147483648 можа быць захаваны ў Int , тып л не павінна мець значэння ні ў адным з выпадкаў.
дададзена аўтар P.P., крыніца
Так, вы маеце рацыю. Я, здаецца, забываюць, што гэтая рэч 2147483648 перапаўняецца Int ;-) Але ўсё ж доўгі павінен з'явіцца правільна працаваць, як сказана ў маім папярэднім каментары.
дададзена аўтар P.P., крыніца
Прыемна працытаваць з стандарту C11 (які ў дадзеным выпадку практычна ідэнтычны стандарту C99), але так як многія праграмісты C выкарыстоўваць як GCC або кампілятар, які імкнецца быць сумяшчальны з GCC, варта адзначыць, што па змаўчанні, GCC не выкарыстоўвае спіс тыпаў вы цытуеце, але замест таго, каб спіс C90 пашыраны ў канцы з больш буйнымі нестандартнымі тыпамі: blog.frama-c.com/index.php?post/2012/01/20/Constants-quiz
дададзена аўтар Pascal Cuoq, крыніца
Калі вы карыстаецеся Int L; вы атрымаеце правільнае значэнне праз пераліў. <�Код> -2147483648 аналізуецца з дапамогай GCC, як унарный мінус прымяняецца да без знака доўгага кода </> (фактычны вынік 2147483648 ), і гэта значэнне пераўтворыцца ў Int , прысвоенае л . Пасля пераўтварэнні, значэнне становіцца -2147483648 .
дададзена аўтар Pascal Cuoq, крыніца
Мне вельмі цікава, што кампілятар зрабіў, хоць, калі ён убачыў ключавое слова ён думаў, што ён павінен быў неадкладна звяртацца і замяніць з пастаянным значэннем, але потым убачыў выраз ўнутры. Я б чакаць, што гэта будзе альбо, 1: ня кампіляваць 2: зрабіць матэматыку на працягу некаторага абмежаванага падмноства выразаў ці 3: пераход да рэалізацыі падчас выканання SizeOf (які, відаць, выкарыстоўваная для дынамічных памераў масіваў, дзе памер перадаюцца як параметр INT Foo [3 * п + 1]; SizeOf (Foo); у гэтым выпадку былі б выкананы множанне.
дададзена аўтар xaxxon, крыніца

Для вашага наступнага пытання, няма «аператара», і няма ніякай розніцы паміж «часам кампіляцыі» памерам выразы, а памерам «час працы».

Калі вы хочаце ведаць, ці з'яўляецца дадзены тып можа ўтрымліваць вынік, які вы шукаеце, вы заўсёды можаце паспрабаваць нешта накшталт гэтага:

#include 
#include 

int main(void) {
    int a = 1250000000;
    int b = 2;

    if ( (INT_MAX/(double) b) > a ) {
        printf("int is big enough for %d * %d\n", a, b);
    } else {
        printf("int is not big enough for %d * %d\n", a, b);
    }

    if ( (LONG_MAX/(double) b) > a ) {
        printf("long is big enough for %d * %d\n", a, b);
    } else {
        printf("long is not big enough for %d * %d\n", a, b);
    }

    return 0;
}

і (трохі) больш агульнае рашэнне, толькі для жаўрукоў:

#include 
#include 
#include 

/* 'gssim' is 'get size of signed integral multiplication */

size_t gssim(long long a, long long b);
int same_sign(long long a, long long b);

int main(void) {
    printf("size required for 127 * 1 is %zu\n", gssim(127, 1));
    printf("size required for 128 * 1 is %zu\n", gssim(128, 1));
    printf("size required for 129 * 1 is %zu\n", gssim(129, 1));
    printf("size required for 127 * -1 is %zu\n", gssim(127, -1));
    printf("size required for 128 * -1 is %zu\n", gssim(128, -1));
    printf("size required for 129 * -1 is %zu\n", gssim(129, -1));
    printf("size required for 32766 * 1 is %zu\n", gssim(32766, 1));
    printf("size required for 32767 * 1 is %zu\n", gssim(32767, 1));
    printf("size required for 32768 * 1 is %zu\n", gssim(32768, 1));
    printf("size required for -32767 * 1 is %zu\n", gssim(-32767, 1));
    printf("size required for -32768 * 1 is %zu\n", gssim(-32768, 1));
    printf("size required for -32769 * 1 is %zu\n", gssim(-32769, 1));
    printf("size required for 1000000000 * 2 is %zu\n", gssim(1000000000, 2));
    printf("size required for 1250000000 * 2 is %zu\n", gssim(1250000000, 2));

    return 0;
}

size_t gssim(long long a, long long b) {
    size_t ret_size;
    if ( same_sign(a, b) ) {
        if ( (CHAR_MAX/(long double) b) >= a ) {
            ret_size = 1;
        } else if ( (SHRT_MAX/(long double) b) >= a ) {
            ret_size = sizeof(short);
        } else if ( (INT_MAX/(long double) b) >= a ) {
            ret_size = sizeof(int);
        } else if ( (LONG_MAX/(long double) b) >= a ) {
            ret_size = sizeof(long);
        } else if ( (LLONG_MAX/(long double) b) >= a ) {
            ret_size = sizeof(long long);
        } else {
            ret_size = 0;
        }
    } else {
        if ( (SCHAR_MIN/(long double) llabs(b)) <= -llabs(a) ) {
            ret_size = 1;
        } else if ( (SHRT_MIN/(long double) llabs(b)) <= -llabs(a) ) {
            ret_size = sizeof(short);
        } else if ( (INT_MIN/(long double) llabs(b)) <= -llabs(a) ) {
            ret_size = sizeof(int);
        } else if ( (LONG_MIN/(long double) llabs(b)) <= -llabs(a) ) {
            ret_size = sizeof(long);
        } else if ( (LLONG_MIN/(long double) llabs(b)) <= -llabs(a) ) {
            ret_size = sizeof(long long);
        } else {
            ret_size = 0;
        }
    }
    return ret_size;
}

int same_sign(long long a, long long b) {
    if ( (a >= 0 && b >= 0) || (a <= 0 && b <= 0) ) {
        return 1;
    } else {
        return 0;
    }
}

які, у маёй сістэме, выхады:

size required for 127 * 1 is 1
size required for 128 * 1 is 2
size required for 129 * 1 is 2
size required for 127 * -1 is 1
size required for 128 * -1 is 1
size required for 129 * -1 is 2
size required for 32766 * 1 is 2
size required for 32767 * 1 is 2
size required for 32768 * 1 is 4
size required for -32767 * 1 is 2
size required for -32768 * 1 is 2
size required for -32769 * 1 is 4
size required for 1000000000 * 2 is 4
size required for 1250000000 * 2 is 8
2
дададзена

Іншы спосаб пакласці адказ павінен сказаць, што тое, што мае дачыненне да SIZEOF не з'яўляецца значэннем выразы, але гэта тып. <�Код> SizeOf вяртае памер памяці для такога тыпу, які можа быць прадугледжаны альбо відавочна, як тып ці як выраз. У гэтым выпадку кампілятар будзе вылічаць гэты тып падчас кампіляцыі без на самой справе вылічэнні выразы (вынікаючы вядомым правілах, напрыклад, калі вы выклікаеце функцыю, атрыманы тып з'яўляецца тыпам вяртаецца значэння).

Як было паказана іншы постэр ёсць выключэнне для зменнай даўжыні масіва (памер, тып якога вядомы толькі падчас выканання).

Іншымі словамі вы звычайна пішуць такія рэчы, як SizeOf (тып) або SizeOf выраз , дзе выраз з'яўляецца L-значэнне. Выраз амаль ніколі не складанае вылічальнае (як дурны прыклад выкліку функцыі вышэй): гэта было б бескарысна ў любым выпадку, паколькі яна не ацэньваецца.

#include 

int main(){
    struct Stype {
            int a;
    } svar;
    printf("size=%d\n", sizeof(struct Stype));
    printf("size=%d\n", sizeof svar);
    printf("size=%d\n", sizeof svar.a);
    printf("size=%d\n", sizeof(int));

}

Таксама зьвярніце ўвагу, што, як SizeOf з'яўляецца мова ключавымі словамі, а не функцыя дужкі ня трэба перад выразам кіраванага (мы маем такія ж правілаў для вяртання ключавога слова).

2
дададзена

The C11 Draft is here: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf You can find the Cx0 draft here: http://c0x.coding-guidelines.com/6.5.3.4.html

У абодвух выпадках, раздзел 6.5.3.4 з'яўляецца тое, што вы шукаеце. У прынцыпе, ваша задача зводзіцца да наступнага:

// Example 1:
long long x = 2500000000;
int size = sizeof(x);//returns 8

// Example 2:
int x = 1250000000;
int y = 2;
int size = sizeof(x * y);//returns 4

У прыкладзе 1, у вас ёсць доўгі доўгі (8 байт), таму яна вяртае 8. У прыкладзе 2, у вас ёсць Int * Int які вяртае Int , які складае 4 байта (так вяртае 4).

Для таго, каб адказаць на ваша пытанне Баунті: так, і няма. <�Код> SizeOf не будзе вылічаць памер, неабходны для аперацыі, якую вы спрабуеце выканаць, але паведаміць вам памер вынікаў пры выкананні аперацыі з адпаведнымі этыкеткамі:

long long x = 1250000000;
int y = 2;
int size = sizeof(x * y);//returns 8

// Alternatively
int size = sizeof(1250000000LL * 2);//returns 8

Вы павінны сказаць яму, што вы маеце справу з вялікім лікам ці ён будзе лічыць, што мае справу з найменшай тыпам ён можа (у дадзеным выпадку Int ).

0
дададзена

Самы просты адказ у адной лініі:

<�Моцны> SizeOf() з'яўляецца функцыяй ацэньваецца падчас кампіляцыі, хто ўваход тыпу С, значэнне якога цалкам ігнаруецца </моцны>

Больш падрабязная інфармацыя: ..therefore, як 2500000000 скампіляваны ён павінен захоўвацца як доўга, як гэта занадта доўга, каб змясціцца ў міжнар, таму гэты аргумент проста скампіляваны як «(тыпу) доўга». Тым не менш, 1250000000 і 2 абодва змесцяцца ў тыпе «INT», такім чынам, што тып перадаецца SIZEOF, так як атрыманае значэнне не захоўваецца, як, таму што кампілятар проста зацікаўлены ў тыпе, множанне ніколі не ацэньваецца.

0
дададзена

Так, SizeOf() не вылічае памер памяці, неабходны для выніку гэтага множання.

У другім выпадку абодва литералов: 1250000000 і 2 кожны патрабуе 4 байта вяртаецца памяці, такім чынам, SizeOf() 4 </код >. Калі адзін з значэнняў быў вышэй 4294967295 (2 ^ 32 - 1) , вы атрымалі б 8 .

Але я не ведаю, як SizeOf() вяртала 8 для 2500000000 . Яна вяртае 4 на маёй VS2012 кампілятара

0
дададзена
@JacobPollack я ўжо адказаў на гэта. Выраз 1250000000 * 2 мае 4 байта, выдзелены яму, калі яны выкарыстоўваюцца ва ўмовах, калі вылучэнне неабходна. І вынік выразы не 2500000000 .
дададзена аўтар Luchian Grigore, крыніца
@LuchianGrigore я ведаю. Калі 4 байта вылучаецца, ён проста будзе пералівацца і даць некаторыя неадназначныя 4 байтавая цэлае. Дзякуючы чалавеку.
дададзена аўтар Jacob Pollack, крыніца
2,5b доўгі, вось чаму. Ёсць у любым выпадку, каб вызначыць аб'ём памяці, выдзеленай для выражэння або зменнай падчас выканання?
дададзена аўтар Jacob Pollack, крыніца
2500m доўгі, гэта значыць 8 байт.
дададзена аўтар Jacob Pollack, крыніца
@ Apocalyp5e - Так! гэта была мая памылка. Але, у любым выпадку VC кампілятар кажа 4294967295 і, такім чынам, 2500000000 , які ніжэй, займае 4 байта і 4294967296 (2 ^ 32) occpies 8bytes. Такім чынам, гэты кампілятар можа апрацоўваць литералы як UINT права? :)
дададзена аўтар Aravind, крыніца
Максімальна магчымае значэнне 4 байта 4294967295. Тады як прыходзіць 2500000000, якая знаходзіцца ніжэй, што патрабуе 8 байт памяці ???
дададзена аўтар Aravind, крыніца
@AravindMeppallil Падпісаны дыяпазон Integer з'яўляецца -2147483648 да 2147483647. без знака Дыяпазон значэнняў ад 0 да 4294967295. :)
дададзена аўтар Apocalyp5e, крыніца